最近正在学习算法动态规划,所以做一个小的总结,以下包含思维导图,重点详细介绍,例题分析。希望对大家学习有所帮助。
下面是思维导图,基本包含动态规划的知识点
现在给大家详细的介绍一下思维导图里的内容
1.动态规划的基本思想
2.动态规划的主要特征和适用条件
整个求解过程是多步判断,从小到大依次求解每个子问题,最后求解的子问题就是原始问题。
子问题目标函数的最小值之间存在着依赖关系,所以要保存子问题的解以备后用。
优化原则(最优子结构):一个最优决策序列的任何子序列本身一定是相对于子序列的初始和结束状态的最优的决策序列。
3.基本要素
动态规划的基本要素就是:最优子结构和重叠子问题。
当问题的最优解包含了其子问题的最优解时,就称该问题具有最优子结构性质
而重叠子问题即反复解同样的子问题,动态规划正是利用了这一种子问题的重叠性质,对每个子问题只求解一次,然后将其保存在一个表格中,当再次需要解此子问题时,只需要简单的常数时间查看一下结果。
4.步骤
(1)找出最优解的性质,并刻画其结构特征
这一步是动态规划的第一步, 首先我们要做的肯定就是分析问题,先判断是否具有最优子结构的性质,这里可以简单证明一下,用剪贴法。
(2)递归地定义最优值
这一步就是要分析出状态转移方程,只要状态转移方程找出来了,后面的代码什么就好解决了。
5.动态规划法的变形-备忘录方法
备忘录方法为每一个子问题建立一个记录项,初始化时,该记录项存入一个特殊值,表示该子问题未被求解,在求解过程中,对每个待求的子问题,首先查看其相应的记录项。若记录项存储的是初始化的值,则表示第一次遇见,此时计算并存入,下次遇见直接提取就好,使算法的复杂度降低。
6. 应用范例
应用范例很多,这边挑一个按照步骤简单讲解一下
0-1背包问题
问题描述:
给定n种物品和一背包,背包i的重量是wi,其价值为vi,背包容量为w。问应该如何选择装入背包中的物品,使得装入背包中物品的总价值最大?
问题分析:
我们可以把这个问题想象成一个超市促销活动,在一定时间内一个购物车让你在超市里任意装入,看谁装的总价值最大。
在选择装入物品时,对于每种物品i有两种选择,装或者不装,但是只能装一次,而且是整个装入。这种问题成为0-1背包问题。
形象化描述为
(1)最优子结构性质(字丑还请见谅哈)
反证法
2.递归关系
用m[i][j]表示最优值,即m[i][j]的背包容量为j,可选择物品为i,i+1,,,,n时的最优值。
m[i][j],将前i个物品放入承重为j的背包中,那么此情况可以分为两种,一个是包含第i个物品(加进去价值变大,且i的重量足够装进去,一个是不包含第i个物品(可以装的下但是加进去价值比m[i-1][j]小;另一种情况是装不下)。
动态转移方程为:
物理意义:
- m[i][j]的物理意义时在背包限容量为j的情况下装入第i个物品的最大价值
- w[i-1]<=j,代表背包限容量为j的情况下可以装的下这第i个物品,则需要进行判断,装下去后的最大价值和不装的最大价值,取最优
- w[i-1]>j,代表此时装不下这个物品,即此时的最大价值为m[i-1][j]
3.自底向上进行求解(可以画图理解)
部分重要代码如下
int findvalue(){//找到最优值
int N,W,i,j;
N=n+1;
W=w+1;
for(i=0;i<N;i++)
f[i][0]=0;
for(i=0;i<W;i++)
f[0][i]=0;
for(i=1;i<N;i++){
for(j=1;j<W;j++){
if(weight[i-1]<=j){//装得下
f[i][j]=max(value[i-1]+f[i-1][j-weight[i-1]],f[i-1][j]);
}
else if(weight[i-1]>j){//装不下
f[i][j]=f[i-1][j];
}
}
}
return f[n][w];
}
void fbmethod(int count[]){//找到最优装入方案
int i,j;
i=n;j=w;
while(i>0&&j>0){
if(f[i][j]!=f[i-1][j]){
count[i-1]=1;j=j-weight[i-1];
i--;
}
else{
i--;
}
}
}
得到最优解:可以利用回溯法
4.给出最优解
刚开始学的话会是有难度的,但是慢慢分析还是能理解的!加油!