经典的01背包问题,去年集训的时候没有做出来的题目,原来是如此简单。。。
思路:
dp[i+1][j]代表选前i个骨头总容量不超过j的最大价值,所以可得到状态方程
|dp[i+1][j] = dp[i][j](vol[i] > j当前i的容量大于j) |
|dp[i+1][j] = max{dp[i][j],dp[i][j-vol[i]]+val[i]}|(当前i的容量小于j,只存在装与不装第i个骨头,所以选择最大的即可)
贴代码:
<span style="font-family:Courier New;font-size:18px;">#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<vector> #include<set> #include<string> #include<algorithm> using namespace std; int dp[1005][1005]; int vol[1005]; int val[1005]; int main() { int T,v,i,j,n; cin >> T; while(T--) { cin >> n >> v; for(i=1; i<=n; i++) cin >> val[i]; for(i=1; i<=n; i++) cin >> vol[i]; for(i=0; i<=v; i++) dp[1][i] = 0; for(i=1; i<=n; i++) { for(j=0; j<=v; j++) { if(j < vol[i]) dp[i+1][j] = dp[i][j]; else dp[i+1][j] = max(dp[i][j],dp[i][j-vol[i]]+val[i]); } } cout << dp[n+1][v] << endl; } return 0; } </span>
又学会了一维数组实现方法,来补一下,其实这道题目只用到了dp[i+1][j]和dp[i][j],所以呢,我们没有必要用两个数组,dp[i]完全就可以了,只要我们保证在求dp[i+1][j]的时候知道dp[i][j]的值就可以了,可以设一个一维数组,容量遍历的时候必须从大往小遍历,因为这样可以保证dp[j] = dp[j+1] + dp[j-vol[i]]+val[i]和dp[i+1][j] = dp[i][j] + dp[i][j-vol[i]]+val[i]作用相同,因为计算j是大容量是要用到j是小容量的时候,所以要想保证求i的时候一维数组dp[i]是前一行的,就要往小的地方遍历。
代码:
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<vector> #include<set> #include<string> #include<algorithm> using namespace std; int d[1005]; int vol[1005]; int val[1005]; int main() { int T,n,m,i,j; cin >> T; while(T--) { cin >> n >> m; for(i=1; i<=n; i++) cin >> val[i]; for(i=1; i<=n; i++) cin >> vol[i]; memset(d,0,sizeof(d)); for(i=1; i<=n; i++) for(j=m; j>=vol[i]; j--) { d[j] = max(d[j],d[j-vol[i]]+val[i]); } cout << d[m] << endl; } return 0; }
(我必须明白写博客不能在乎排名多少,虽然我现在已经有排名了,不能关注访问量,要多记录一些知识点,供别人和自己更好的更完美的理解知识,学东西要深入,要切切实实弄懂,要为自己而学。)