01背包问题求解思路
①、确认子问题和状态
01背包问题需要求解的就是,为了体积V的背包中物体总价值最大化,NN件物品中第ii件应该放入背包中吗?(其中每个物品最多只能放一件)
为此,我们定义一个二维数组,其中每个元素代表一个状态,即前ii个物体中若干个放入体积为VV背包中最大价值。数组为:f[N][V]f[N][V],其中fijfij表示前ii件中若干个物品放入体积为jj的背包中的最大价值。
②、初始状态
初始状态为f[0][0−V]f[0][0−V]和f[0−N][0]f[0−N][0]都为0,前者表示前0个物品(也就是空物品)无论装入多大的包中总价值都为0,后者表示体积为0的背包啥价值的物品都装不进去。
if (背包体积j小于物品i的体积) f[i][j] = f[i-1][j] //背包装不下第i个物体,目前只能靠前i-1个物体装包 else f[i][j] = max(f[i-1][j], f[i-1][j-Vi] + Wi)
最后一句的意思就是根据“为了体积V的背包中物体总价值最大化,NN件物品中第ii件应该放入背包中吗?”转化而来的。ViVi表示第ii件物体的体积,WiWi表示第ii件物品的价值。这样f[i-1][j]代表的就是不将这件物品放入背包,而f[i-1][j-Vi] + Wi则是代表将第i件放入背包之后的总价值,比较两者的价值,得出最大的价值存入现在的背包之。
我们做的转化就是,把除了最大菜价之外,其他的菜价装入一个sum-5 的背包里,看最大能装多少。
理论:http://www.cnblogs.com/fancy-itlife/p/4393213.html
首先看第一个条件—最优子结构。最大的装入量一定是如果装入第i个或者不装入第i个的两个选择之一。
第二个条件—子问题重叠。当完成一个阶段比如装第i个,我下面做的是对第i-1个进行抉择,你可以发现跟前面的问题一样,装还是不装两个选择之一。这就是所谓的子问题重叠。
#include<bits/stdc++.h> using namespace std; #define maxn 1005 int a[maxn],dp[maxn]; int main() { int n,v; while(cin>>n) { memset(dp,0,sizeof(dp)); if(!n) break; for(int i=0; i<n; i++) cin>>a[i]; cin>>v; if(v<5) { cout<<v<<endl; continue; } sort(a,a+n); for(int i=0; i<n-1; i++) for(int j=v-5; j>=a[i]; j--) dp[j]=max(dp[j],dp[j-a[i]]+a[i]); cout<<v-dp[v-5]-a[n-1]<<endl; } return 0; }