递归的参数:(i, m, sum):i表示当前是物品的序号,m表示背包的体积,sum表示的是当前背包里面所容纳的物品的价值的总和。
递归的出口:当 n 件物品都已经枚举完毕后,更新答案,然后返回!
递归体:每件物品都只有两个选择,选或不选,如果不选的话,那么当前背包的价值即为从前 i - 1 件物品里面选,的最大价值。所以可以直接递归到下一个物品。如果当前物品选的话,则需要预先判断当前背包的空间是否能够容纳,若能够容纳,再将其装入背包,同时记得更新参数!
代码:
#include<iostream>#include<cstring>#include<algorithm>usingnamespace std;constint N =1e3+10;int w[N], v[N];int res;int n, m;voiddfs(int i,int m,int sum){if(i == n+1){
res =max(res, sum);return;}dfs(i+1, m, sum);if(m >= v[i])dfs(i +1, m - v[i], sum + w[i]);}intmain(){
cin >> n >> m;for(int i=1; i <= n; i ++){
cin >> v[i]>> w[i];}dfs(1, m,0);
cout << res << endl;return0;}
计算:从前 i 件物品里面选,那么说明前 i - 1件物品已经选好了,只需要考虑第 i 件物品选还是不选,决策选还是不选取决于的是哪种决策下,价值最大,所以说取一个max值即可!若不选第 i 个物品,则更新为:f[i][j] = f[i-1][j];反之为:f[i][j] = max(f[i-1][j], f[i-1][j-v[i]] + w[i]);
代码:
#include<iostream>#include<cstring>#include<algorithm>usingnamespace std;constint N =1e3+10;int f[N][N];intmain(){int n, m;
cin >> n >> m;for(int i=1; i <= n ;i ++){int v, w;
cin >> v >> w;for(int j=1; j <= m; j ++){
f[i][j]= f[i-1][j];if(j >= v){
f[i][j]=max(f[i][j], f[i-1][j-v]+ w);}}}
cout << f[n][m]<< endl;return0;}
一维DP的写法:
思路:
集合:从前n种物品里面选,容积为m的背包的最大价值。
属性:max
计算:考虑两个问题,为什么可以二维变一维?为什么需要保证逆序?实际上这两个问题是一个关联性极其强大的问题:二维变一维,是因为每次第 i 层的f[i][j] 更新都只用到了第 i - 1层的f[i-1][…],所以说,可以省去第一维度;对于第二个问题,其实也是对于第一个问题的保证,保证能够正确地更新!何出此言?逆序可以保证第 i 层更新的时候,用的是第 i - 1层的数据,而正序更新的话,则会导致用第 i 层刚更新的数据,去更新第 i 层当前的数据。如图所示:
代码:
#include<iostream>#include<cstring>#include<algorithm>usingnamespace std;constint N =1e3+10;int f[N];intmain(){int n, m;
cin >> n >> m;for(int i=1; i <= n; i ++){int v, w;
cin >> v >> w;for(int j=m; j >= v; j --){
f[j]=max(f[j], f[j-v]+ w);}}
cout << f[m]<< endl;return0;}