当前位置:网站首页>一道题讲解动态规划的前世今生
一道题讲解动态规划的前世今生
2022-06-10 17:44:00 【星光技术人】
题目:给一个数组Arr=[2,3,5,7,5],aim=10;得出数组中组成aim的元素个数最少是多少;
下面从三个方面依次解题,逐步从递归解法过渡到动态规划
1. 暴力递归
- 思路
设f(index,aim)表示从index开始的硬币中,组成aim的最小硬币数;那么我们的目标为f(0,10);
f(index,aim) = min(f(index+1,aim),1+f(index+1,aim-Arr[index]))
第一项表示不用第index个硬币;第二项表示使用index个硬币
/********************暴力递归****************/
//index表示从index个硬币开始选择
//rest表示还剩下多少钱数需要凑
//返回index开始以后的硬币还需要使用rest个
int process1(vector<int>& Arr, int index, int rest)
{
if (rest < 0)
return -1;
if (rest == 0)
return 0;
//rest>0但是硬币没了
if (index == Arr.size())
return -1;
//rest>0并且还有硬币
int p1 = process1(Arr, index + 1, rest);
int p2Next = process1(Arr, index + 1, rest - Arr[index]);
if (p1 == -1 && p2Next == -1)
return -1;
else if (p1 == -1)
return p2Next + 1;
else if (p2Next == -1)
return p1;
return min(p1, 1 + p2Next);
}
//得到最小的硬币数
int get_mincoin1(vector<int>& Arr, int aim)
{
return process1(Arr, 0, aim);
}

2. 记忆搜索解法
第一种解法,会出现重复计算的情况,如同f(3,5)会在两个分支上都计算一遍,这就造成了计算资源的浪费;所以记忆搜索解法相比第一种暴力递归解法添加存储机制,保存已经计算过的f(index,rest)的值;当再次遇到的时候,直接使用,不在重复计算
- code
/*************记忆搜索*************/
int process2(vector<int>& Arr, int index, int rest,vector<vector<int>>& dp)
{
if (rest < 0)
return -1;
if (dp[index][rest] != -2)
return dp[index][rest];
if (rest == 0)
dp[index][rest] = 0;
//rest>0
else if (index == Arr.size())
dp[index][rest] = -1;
else
{
//rest>0 还有硬币
int p1 = process2(Arr, index + 1, rest,dp);
int p2Next = process2(Arr, index + 1, rest - Arr[index],dp);
if (p1 == -1 && p2Next == -1)
dp[index][rest] = -1;
else if (p1 == -1)
dp[index][rest] = p2Next + 1;
else if (p2Next == -1)
dp[index][rest] = p1;
else
dp[index][rest] = min(p1, 1 + p2Next);
}
return dp[index][rest];
}
int get_mincoin2(vector<int>& Arr, int aim)
{
vector<vector<int>> dp(Arr.size() + 1, vector<int>(aim + 1, -2));
return process2(Arr, 0, aim, dp);
}
3. 严格表结构
严格表结构就是大家说的动态规划,状态转移矩阵;在从记忆搜索解法往严格表结构转换的时候,需要有一下几个步骤
1) 找出可变参数个数和范围,用于定义dp数组;
2) 需要根据记忆搜索算法的if条件,确定dp数组中不需要计算的位置;
3) 寻找表中其他位置的位置依赖的规律
状态转移矩阵的大概形式(还需要根据细节划分)
dp(index,aim) = dp(f(index+1,aim),1+dp(index+1,aim-Arr[index]))
- code
/*************严格表结构*************/
int get_mincoin3(vector<int>& Arr, int aim)
{
vector<vector<int>> dp(Arr.size() + 1, vector<int>(aim + 1,0));
for (int index = 0; index < Arr.size(); index++)
dp[index][0] = 0;
for (int rest = 1; rest <= aim; rest++)
dp[Arr.size()][rest] = -1;
for (int index = Arr.size() - 1; index >= 0; index--)
{
for (int rest = 1; rest <= aim; rest++)
{
int p1 = dp[index + 1][rest];
int p2Next = -1;
if(rest - Arr[index] >= 0)
p2Next = dp[index + 1][rest - Arr[index]];
if (p1 == -1 && p2Next == -1)
dp[index][rest] = -1;
else if (p1 == -1)
dp[index][rest] = p2Next + 1;
else if (p2Next == -1)
dp[index][rest] = p1;
else
dp[index][rest] = min(p1, 1 + p2Next);
}
}
return dp[0][aim];;
}
4. 总结
实际上,动态规划题目最终的状态转移矩阵的本质都是由第一解法暴力递归转化过来的;最重要的还是要确定递归的思路,而递归思路的确定的前提,就是找到变换的参数index和rest;所以最重要的就是找到这两个变化的参数和递归的思路,然后状态转移矩阵就可以迎刃而解;
动态规划中,重要的还有遍历的顺序和变换参数的范围
边栏推荐
- .NET 开源的免费午餐结束了?
- (CVPR 2020) RandLA-Net: Efficient Semantic Segmentation of Large-Scale Point Clouds
- Adding rendererdata of URP with script
- 阅读micropyton源码-添加C扩展类模块(4)
- c语言---6 初识选择语句、循环语句、函数以及数组
- 内存池原理一(基于整块)
- Talk about those things about telecommuting, participate in the essay solicitation, receive the contribution fee and win the grand prize!
- c语言---7 初识操作符
- ACL2022 | bert2BERT:参数复用的高效预训练方法,显著降低超大模型的训练成本
- 2022上半年信息系统项目管理师论文真题
猜你喜欢

Library for adding progress bar during training --tqdm

Abbexa丙烯酰胺-PEG-NHS说明书

NaturalSpeech模型合成语音在CMOS测试中首次达到真人语音水平

掌握高性能计算前,我们先了解一下它的历史

Cdga| six key points of data governance for industrial enterprises

XML & XPath parsing

JS blur shadow follow animation JS special effect plug-in

c语言---11 分支语句if else

AI 加持实时互动|ZegoAvatar 面部表情随动技术解析

使用DAP-Link单独下载可执行文件到MM32F5微控制器
随机推荐
XML&Xpath解析
基于业务沉淀组件 =&gt; manage-table
Wireshark learning notes (I) common function cases and skills
Library for adding progress bar during training --tqdm
LeetCode 255. Verifying preorder traversal sequence binary search tree*
Abbexa 8-OHdG CLIA 试剂盒解决方案
搭建在线帮助中心,轻松帮助客户解决问题
C语言在底层如何对double和float压栈
AI 加持实时互动|ZegoAvatar 面部表情随动技术解析
Qtablewidget / qtableview practical tips
Abbexa AML1 DNA 结合 ELISA 试剂盒说明书
c语言学习回顾---1 基础知识回顾
This article introduces you to j.u.c's futuretask, fork/join framework and BlockingQueue
美学心得(第二百三十七集) 罗国正
What is image search
踩坑了,BigDecimal 使用不当,造成P0事故!
YML file configuration parameter definition dictionary and list
CDGA|工业企业进行数据治理的六个关键点
Generate XML based on annotations and reflection
c语言---5 初识字符串、转义字符、注释