动态规划总结(01背包 完全背包 多重背包)
来源:互联网 发布:淘宝快递拒签运费谁负 编辑:程序博客网 时间:2024/04/30 15:22
动态规划总结(01背包 完全背包 多重背包)
一、学习资料
1.UVA DP 入门专题
2.夜深人静写算法(二) - 动态规划
3.算法之动态规划
4.什么是动态规划?动态规划的意义是什么?
5.01背包问题和完全背包问题
6.背包九讲
二、练习题目
1.01背包练习
2.完全背包 多重背包练习
3.UVA的部分题目
三、模型总结
(1)01背包问题
1.模型大意
有n件商品,每件商品仅有一件,并且每件商品有自己的价值v和重量w。现在有一个最大承载重量为m的背包,求解最多能装下价值为多少的商品。
2.状态转移方程
dp[j] = max(dp[j],dp[j-w[i]]+v[i])
3.核心代码片
for(int i =1; i<=n;++i){ for(int j = m; j>=w[i];--j) dp[j] = max(dp[j],dp[j-w[i]]+v[i]); }
4.习题小结
1).HDOJ.2955
结合了概率和独立事件的知识。对于每个银行,小偷有抢或者不抢两种选择,并且每个银行抢不抢,事件发生时独立的。两个独立事件共同发生的概率,为两个事件发生概率的乘积。这是需要注意的。 另外一点就是,在遇到一些概率的问题的时候,通常需要将其转换成其对立事件发生的概率。这样解决起来较为容易。
2).HDOJ.3466
题面本身就是一个简单的01背包问题但是关键在于本题却需要排序,原因是会影响到后续物品的选择。简单来说,破坏了动态规划的无后效性。
对于每个商品,尤其能够买的临界值qi和其本身的价格pi,即当手中的钱不够qi的时候,商人就不考虑把第i件商品卖给你了。 比如有以下商品:
其中 q1 – p1 < q2 – p2
若想把这两件商品全部购买,则至少需要p1+p2的金钱。那么如果我们没有这么多金钱怎么办。这就要考虑到dp时候的状态转移了。
在状态转移的时候,item1能从item2转移的状态区间是[min(q1+p2,m),m],同理,item2能从item1转移的状态区间是[min(q2+p1,m),m]。对于p1+q2或p2+q1,个人的理解是,先买了物品1花费p1,因为现在要对物品2进行状态转移,则需要钱的数量大于q2才可以,否则无法进行状态转移,即物品1的状态没有得到利用,因为我们要尽可能重复的利用这个区间。(p2+q1同理可得)
故对于以上2件商品,我们要看p1+q2和p2+q1孰大孰小。再根据题目数据不难看出 p1 + q2 < p2 + q1。
根据以上的叙述不难得出结论:要按qi-pi的差值升序排序,然再做01背包。那么疑问也油然而生:为什么平常的做01背包也没见排序呀? 这是因为普通的01背包pi==qi,也就是说只要有足够的金钱,就能购买物品。故不需要排序。所以以后做这种类型的dp要留个心眼。
3).HDOJ.2546
这题跟上面的那个题目也有相似之处,由于此题恒定q为5,我们可以采用别的方法来处理。先按照价格降序/升序排序,然后把价格最大的那个留下来(留给那个剩余的5块钱,一边让剩余金额最小)。然后以总金额-5为背包容量,除去最贵的剩余菜为商品做01背包即可。
4).HDOJ.2639
此题本身依旧是一个01背包,但是题目要求输出的是第k最优解,平常题目都是直接输出最优解即可。
根据背包九讲,不难想到肯定要增加一维,使得dp变为二维数组,其中第二维用来表示第K最优解。其次分别2个辅助数组a[],b[],容量以题目中的K为上限。实现方法如下:
a.在做01背包的时候,多增加一层循环,由1->k的循环,用来储存第K个解。将原本的01背包状态转移方程中较大的放到a[]中,较小的放到b[]中。
b.其次对a[],b[]做处理,依次从这2个数组中取出较大的那个,放到dp[i][k].表示第k解。
代码如下:
for(int i = 1;i<=n;++i){ for(int j =m;j>=w[i];--j){ int l; for( l = 1;l<=k;l++){ a[l] = dp[j-w[i]][l]+v[i]; b[l] = dp[j][l]; } a[l] = b[l] = -1; int x,y,z; x = y= z = 1; while(z<=k && (a[x]!=-1 || b[y]!=-1)){ if(a[x] > b[y]){ dp[j][z] = a[x];x++;} else {dp[j][z] = b[y];y++;} if(dp[j][z] != dp[j][z-1]) z++; } } }
5.总结
1). 不要忘记初始化dp数组,和其他的辅助数组。
2). 在求一些最大最小值,或者是否可以构成的时候,经常讲dp整个初始化为INF,或者将dp[0]初始化为0或者1,这个要具体情况具体分析。
(2)完全背包问题
1.模型大意
有n件商品,每件商品有无数件,并且每件商品有自己的价值v和重量w。现在有一个最大承载重量为m的背包,求解最多能装下价值为多少的商品。
2.状态转移方程
dp[j] = max(dp[j],dp[j-w[i]]+v[i])
3.核心代码片
for(int i =1; i<=n;++i){ for(int j = w[i]; j<=m;++j) dp[j] = max(dp[j],dp[j-w[i]]+v[i]); }
4.习题小结
1).UVA.674
经典的硬币组成问题,问某个金额的组成方案有多少种,注意当数据特别大的时候要开long long数组。
2).HDOJ.2159
这题是带个数限制的完全背包,那么最先想到的就是增加一维来表示个数。
for(int i =1; i<=k; ++i) { for(int j = a[i].ence; j<=m; ++j) for(int l = 1; l<=s;++l) dp[j][l] = max(dp[j][l],dp[j-a[i].ence][l-1] +a[i].exp); }
5.总结
总的感觉完全背包没有什么难点,基本上就是套状态转移方程即可。
(3)多重背包问题
1.模型大意
有n件商品,第ai件商品有ci件,并且每件商品有自己的价值v和重量w。现在有一个最大承载重量为m的背包,求解最多能装下价值为多少的商品。
2.状态转移方程
**F[i,v] = max{F[i − 1, v − k ∗ Ci
] + k ∗ Wi
| 0 ≤ k ≤ Mi}**
3.核心代码片
一般集合二进制优化和单调队列优化,转换为01背包问题
4.习题小结
二进制优化
即用二进制来表示有限的状态。通俗点讲,就是用1,2,4,8,16……这样的数来表示任意一个有限数字。如3 = 2+1, 7=4+2+1 如果我们把物品的个数,拆分成1个2个4个……在一起的物品,那么就是相当于对这样的物品做出选择,即做01背包。 这样就由多重背包,转换成了01背包的问题。
二进制优化代码:
for(int i = 0 ;i<6;++i){ for(int j =1; j<=c[i]; j<<=1){ val[cnt] = j*(i+1); num[cnt++] = j; c[i]-=j; } if(c[i]>0){ val[cnt] = c[i] * (i+1); num[cnt++] = c[i]; } }
5.总结
一般大部分题目都是使用二进制优化转换成01背包问题,或者是使用单调队列优化,极大提高程序效率。
(4)LCS问题 – 最长公共子序列
1.模型大意
给出2个字符串,求出这两个字符串的最长公共子序列的长度。
2.状态转移方程
if(c1[i] == c2[j]) dp[i][j] =dp[i-1][j-1]+1;
else dp[i][j] = max(dp[i-1][j],dp[i][j-1]);
3.核心代码片
for(int i =1; i<=len1;++i){ for(int j = 1; j<=len2;++j){ if(c1[i] == c2[j]) dp[i][j] =dp[i-1][j-1]+1; else dp[i][j] = max(dp[i-1][j],dp[i][j-1]); } }
(5)LIS问题 – 最长上升子序列
1.模型大意
给出一个序列,求出他的最长上升子序列的长度。
2.状态转移方程 + 核心代码片
for(int i = 2; i<=n;++i){ if(a[i]>dp[len]) dp[++len] = a[i]; else{ int pos = BS(dp,a,1,len,i); dp[pos] = a[i]; } }int BS(int dt[],int t[],int left, int right,int i){ int mid; while(left<right){ mid = (left+right)/2; if(dt[mid]>=t[i]) right = mid; else left = mid+1; } return left;}
- 动态规划总结(01背包 完全背包 多重背包)
- 动态规划初步( 01 背包、完全背包、多重背包)
- 动态规划-----背包问题-----01背包,完全背包,多重背包
- 动态规划之01背包,完全背包,多重背包
- 动态规划之01背包,完全背包,多重背包模板
- 背包(01背包、完全背包、多重背包)问题总结
- 【动态规划】完全背包、多重背包
- DP总结(1) 01背包 完全背包 多重背包
- 动态规划--背包问题(0-1背包,完全背包,多重背包)
- 背包问题小总结 习题(动态规划01背包(第k优解)完全背包,多重背包)acm杭电HDU2639,HDU2602,HDU1114,HDU2191
- 动态规划背包算法(01背包和完全背包)
- 背包问题总结(01背包、完全背包、多重背包)
- 背包问题(01背包,完全背包,多重背包)
- 背包问题(01背包,完全背包,多重背包)
- 背包模板(01背包,完全背包,多重背包)
- 背包问题(01背包,完全背包,多重背包)
- 背包问题(01背包 + 完全背包 + 多重背包)
- 背包问题(01背包,完全背包,多重背包)
- 2016年寒假学习日记
- 数字
- 多文档类型、视图和框架窗口
- React Native FlexBox布局
- JavaScript 模块的循环加载
- 动态规划总结(01背包 完全背包 多重背包)
- Java编程题练习2017-02-20
- java时间的转换以及时间的比较
- FZU1894-志愿者选拔
- 性能测试7-性能调优
- 图的基本存储的基本方式一
- 中国的创新经济—学习笔记1
- 项目人力资源管理 考纲与考试要点
- NYOJ 78 圈水池(凸包基础)@