dp之01背包(从二维到一维)+完全背包
2017-08-14 17:04
363 查看
☝这是最原始的01背包问题http://101.200.220.237/problem/153/
下面写一下我的想法。
巨巨是这样说的:
能用动规解决的问题的特点
1) 问题具有最优子结构性质。如果问题的最优解所包含的子问题的解也是最优的,我们就称该问题具有最优子结构性质。
2)无后效性。当前的若干个状态值一旦确定,则此后过程的演变就只和这若干个状态的值有关,和之前是采取哪种手段或经过哪条路径演变到当前的这若干个状态,没有关系。
解释一下状态转移方程f[i][j]=max(f[i-1][j],f[i-1][j-weight[i]]+value[i]);
就是第i个物体放入容量为j的背包时所能获得的最大价值,划分了子问题,就是本来背包是m那么大,然后分割成1,2,3…m,那么大,符合第一条,无后效性在自己打表的时候体会比较深刻一些。
继续说状态转移方程,这样的话对于f[i][j],就只存在放或者不放第i个物体这两种选择,前提是能放进去。如果不放,那自然就是直接取f[i-1][j]的值;如果放,这就牵扯到一个“腾地方”的问题,就是你想放进去一个多大的东西,那么就需要给它腾出多大的地方,然后比如腾完了地方如果还有位置还是可以放别的东西的,而这个数据在上一层已经记录,所以就有了f[i-1][j-weight[i]]+value[i]。
样例中的数据打表得出的结果是:
自己把这个表写一遍很重要,写完差不多就懂了。
基本上算是最基本的dp代码了吧。
#include<iostream> using namespace std; #include<algorithm> #include<string> #include<string.h> int main() { int n, m; while (scanf("%d%d", &n, &m) != EOF) { int f[110][1100];//表格记录数值 memset(f, 0, sizeof(f)); int weight[110]; int value[110]; int i, j; for (i = 1; i <= n; i++) scanf("%d%d", &weight[i], &value[i]); for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) { if (weight[i] <= j) f[i][j] = max(f[i - 1][j], f[i - 1][j - weight[i]] + value[i]); //状态转移方程 else 4000 f[i][j] = f[i - 1][j]; } printf("%d\n", f [m]); } return 0; }
今天还学习了一个把二维表简化成一维表的。
据说这个对后续的“背包九讲”的学习有很大的帮助。
开始我以为只是简单地将二维缩成一维,但是当然就不是!
#include<iostream> using namespace std; #include<string.h> #include<algorithm> int main() { int t; cin >> t; while (t--) { int weight[1010]; int value[1010]; int f[10010]; memset(f, 0, sizeof(f)); int n, w; cin >> n >> w; int i,j; for (i = 1; i <= n; i++) cin >> value[i]; for (i = 1; i <= n; i++) cin >> weight[i]; for (i = 1; i <= n; i++) for (j = w; j >=0; j--)//为什么能变成一维 if (weight[i]<=j) f[j] = max(f[j], f[j - weight[i]] + value[i]); cout << f[w] << endl; } return 0; }
跑出来的结果是这样的。(每一个i循环中都把f数组从1到w输出一下)
这个是按照j正序跑出来的结果。
这是为什么呢?就按程序中的跑,正序的时候的一个输出的f数组,那么f[10]=max(f[10],f[5]+value[5]),也就是说这个第一个东西被放进去了两次!如果是从w…0,就不会出现这种情况,这个真的好机智,然后就可以直接算完全背包了!
hdu4508,可是说是完全背包的裸题了
http://acm.hdu.edu.cn/showproblem.php?pid=4508
#include<iostream> using namespace std; #include<algorithm> #include<string.h> int happiness[110]; int cla[110]; int dp[100006]; int main() { int n; while (scanf("%d",&n)!=EOF) { memset(dp, 0, sizeof(dp)); int i; for (i = 0; i < n; i++) scanf("%d%d", &happiness[i], &cla[i]); int m; scanf("%d", &m); int j; for (i = 0; i < n; i++) for (j = cla[i]; j <= m; j++)//仔细感受一下这个循环,可以说是非常机智了 dp[j] = max(dp[j], dp[j - cla[i]] + happiness[i]); printf("%d\n", dp[m]); } return 0; }
相关文章推荐
- DP背包问题小结(01背包,完全背包,需恰好装满或不需,一维DP、二维DP)
- hdu 2159 dp(二维完全背包)
- HDU 3008 dp打怪血量 三重循环调二维背包或一维
- [DP][01背包]01\完全\多重背包模板
- DP背包之01背包、完全背包、多重背包笔记
- dd大牛背包九讲(01,完全,多重,混合,二维,分组等背包)(转载+补充)一万二千字!!!
- HDU3127 二维完全背包 DP
- 背包DP(01背包,多重背包,完全背包)
- 夕拾算法进阶篇:17)01背包和完全背包问题 (动态规划DP)
- 01背包 完全背包 多重背包 二维费用背包
- HDU 2159 FATE (动态规划dp之二维完全背包问题)
- uva10304(二维完全背包DP)
- HDU - 2159 - FATE 【二维完全背包,和一维差不多呀】
- 二维费用 hdu 2159 FATE(完全背包)HDU OJ 4501 小明系列故事——买年货【DP】
- 知识点:01背包(多种姿势:二维实现+一维实现+滚动数组实现+背包装满+输出最优方案)
- HDU 2159 FATE 二维完全背包 dp
- 01背包、完全背包(DP)
- 简单的01背包 HDU - 2602 1864 二维、一维数组
- hdu 3127 WHUgirls 二维完全背包
- poj 1014 -- 01背包 完全背包 多重背包 代码详解