传送门:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1085
第1行,2个整数,N和W中间用空格隔开。N为物品的数量,W为背包的容量。(1 <= N <= 100,1 <= W <= 10000) 第2 - N + 1行,每行2个整数,Wi和Pi,分别是物品的体积和物品的价值。(1 <= Wi, Pi <= 10000)
输出可以容纳的最大价值。
3 6 2 5 3 8 4 9
14
最基本的01背包问题,做的时候程序实在不知道哪错了,但是编译一直是13不是14,索性一交 ,竟然神奇的过了。无语
状态转移方程:dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+p[i]) (j>=w[i]) 这是二维的,空间上没有优化。
对于01背包
面对每个物品,我们只有选择拿取或者不拿两种选择,(这就是拿是1不拿是0)不能选择装入某物品的一部分,也不能装入同一物品多次。
声明一个 大小为 dp[n][w] 的二维数组,dp[ i ][ j ] 表示 在面对第 i 件物品,且背包容量为 j 时所能获得的最大价值 ,那么我们可以很容易分析得出 dp[i][j] 的计算方法,
(1). j < w[i] 的情况,这时候背包容量不足以放下第 i 件物品,只能选择不拿 dp[ i ][ j ] = dp[ i-1 ][ j ]
(2). j>=w[i] 的情况,这时背包容量可以放下第 i 件物品,我们就要考虑拿这件物品是否能获取更大的价值。
如果拿取,dp[ i ][ j ]=dp[ i-1 ][ j-w[ i ] ] + p[ i ]。 这里的dp[ i-1 ][ j-w[ i ] ]指的就是考虑了i-1件物品,背包容量为j-w[i]时的最大价值,也是相当于为第i件物品腾出了w[i]的空间。
如果不拿,dp[ i ][ j ] = dp[ i-1 ][ j ] , 拿还是不拿,比较这两种情况那种价值最大
代码:(怎么都是13,以后再看)
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int dp[150][10050],c[10050],p[10050];
int main()
{
int n,w,i,j;
while(scanf("%d%d",&n,&w)!=EOF)
{
for(i=1;i<=n;i++)
scanf("%d%d",&c[i],&p[i]);
for(i=1;i<=n;i++)
{
for(j=1;j<=w;j++)
{
if(c[i]<=j)
dp[i][j]=max(dp[i-1][j],dp[i-1][j-c[i]]+p[i]);
else
dp[i][j]=dp[i-1][j];
}
}
printf("%d\n",dp[n][w]);
}
return 0;
}
一维
dp数组是从上到下,从右往左计算的。在计算dp[i][j]之前,dp[j]里保存的是dp[i-1][j]的值,而dp[j-w]里保存的是dp[i-1][j-w],因为j是逆序枚举的。(假如顺序枚举的话dp[j-w]保存的会是dp[i][j-w]的值)这样,dp[j]=(max
[j],dp[j-v]+w)实际上是把max{dp[i-1][j],dp[i-1][j-v]}保存在dp[j]中,覆盖掉dp[j]中原来的dp[i-1][j].
一维代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int dp[10050],w[105],p[105];
int main()
{
int n,W,i,j;
// while(scanf("%d%d",&n,&W)!=EOF)
// {
scanf("%d%d",&n,&W);
for(i=1;i<=n;i++)
{
scanf("%d%d",&w[i],&p[i]);
}
memset(dp,0,sizeof(dp));
for(i=1;i<=n;i++)
{
for(j=W;j>=w[i];j--)
dp[j]=max(dp[j],dp[j-w[i]]+p[i]);
}
printf("%d\n",dp[W]);
// }
return 0;
}
令推荐个好玩的博客:http://www.cnblogs.com/sdjl/articles/1274312.html