UVA 624 CD(DP:01背包)
题意:有N个物品,每个物品一个重量,现在问你在重量不超过W的前提下,如何选物品可以使得装的物品尽量多,并且要按输入顺序输出被装入的物品,已经总重量sum.
分析:基础的01背包DP不过需要打印路径,需要熟练.
由于dp[i][j] = max( dp[i-1][j],dp[i-1][j-wi]+wi ).所以用一个二维数组vis[i][j]表示dp[i][j]作出的选择.而且可能存在多种选择的情况,这题目好像不考虑,总是优先维持之前已经选择的物品.
注意:由于打印物品是从前往后打印,所以选物品的时候要从后往前选,则当得到dp[n][nWeight]的时候可以推出第一个物品选没选.
AC代码:
#include <iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std; const int MAXN=10005; int weight[25]; int dp[MAXN]; int nKind,nWeight; bool vis[25][MAXN]; void ZeroOnePack() { for(int i=nKind;i>=1;i--) for(int j=nWeight;j>=weight[i];j--) { if(dp[j-weight[i]]+weight[i]>dp[j]) { dp[j] = dp[j-weight[i]]+weight[i]; vis[i][j]=true; } } } int main() { while(scanf("%d%d",&nWeight,&nKind)==2) { for(int i=1;i<=nKind;i++) scanf("%d",&weight[i]); memset(dp,0,(nWeight+1)*sizeof(dp[0])); memset(vis,false,sizeof(vis)); ZeroOnePack(); int end=nWeight; for(int i=1;i<=nKind;i++) if(vis[i][end]) { printf("%d ",weight[i]); end -=weight[i]; } printf("sum:%d\n",dp[nWeight]); } return 0; }