1.题目描写叙述:点击打开链接
2.解题思路:本题就是经典的01背包问题,i逆序枚举的写法就不介绍了,主要说一下经典的错误写法。假设将输入的n个物品下标设为0~n-1,给出正确的写法和错误的写法。
3.代码:
(正确的写法)
//#pragma comment(linker, "/STACK:1024000000,1024000000") #include<iostream> #include<algorithm> #include<cassert> #include<string> #include<sstream> #include<set> #include<bitset> #include<vector> #include<stack> #include<map> #include<queue> #include<deque> #include<cstdlib> #include<cstdio> #include<cstring> #include<cmath> #include<ctime> #include<cctype> #include<functional> using namespace std; #define me(s) memset(s,0,sizeof(s)) typedef long long ll; typedef unsigned int uint; typedef unsigned long long ull; typedef pair <int, int> P; #define rep(i,n) for(int i=0;i<(n);i++) const int N=1000+10; int w[N],v[N]; int dp[N][N]; int main() { int n,V; int T; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&V); for(int i=0;i<n;i++) scanf("%d",&w[i]); for(int i=0;i<n;i++) scanf("%d",&v[i]); me(dp); for(int i=0;i<n;i++) for(int j=0;j<=V;j++) { dp[i+1][j]=dp[i][j]; if(j>=v[i]) dp[i+1][j]=max(dp[i+1][j],dp[i][j-v[i]]+w[i]); } printf("%d ",dp[n][V]); } }
(错误写法一)
for(int i=0;i<n;i++) for(int j=0;j<=V;j++) { if(!i)dp[i][j]=0; else { dp[i][j]=dp[i-1][j]; if(j>=v[i]) dp[i][j]=max(dp[i][j],dp[i-1][j-v[i]]+w[i]); } } printf("%d ",dp[n-1][V]);
(错误写法二)
for(int i=0;i<n;i++) for(int j=0;j<=V;j++) { if(!i){dp[i][j]=0;continue;} dp[i][j]=dp[i-1][j]; if(j>=v[i]) dp[i][j]=max(dp[i][j],dp[i-1][j-v[i]]+w[i]); } printf("%d ",dp[n-1][V]);
(错误写法三)
for(int i=0;i<n;i++) for(int j=0;j<=V;j++) { dp[i][j]=(i==0)?0:dp[i-1][j]; if(j>=v[i]) dp[i][j]=max(dp[i][j],dp[i-1][j-v[i]]+w[i]); } printf("%d ",dp[n-1][V]);
以上三种错误写法,假设都明确为什么错了。说明真的理解了状态转移方程。