您的位置:首页 > 其它

背包九讲之一(01背包)

2015-02-07 11:38 204 查看
/*
有n个物品和一个容量为V的背包,第i件物品的费用是c[i],价值是w[i]
求解哪些物品装入背包使价值总和最大
dp[i][j]  dp[i][j] 为前i件物品放进容量为j的背包的最大价值
dp[i][j] = max(dp[i-1][j],dp[i-1][j-c[i]]+w[i]);
*/
#include <stdio.h>
#include <string.h>
int dp[111][1111];
int dp2[1001];
int c[111],w[111];
bool flag[111];
inline int max(const int &a, const int &b)
{
return a < b ? b : a;
}
int main()
{
int n,v,i,j;
while(scanf("%d%d",&n,&v)!=EOF)
{
memset(dp,0,sizeof(dp));
dp2[0] = 0;
for(i=1; i<=n; ++i)
dp2[i] = 1<<30;
memset(flag,false,sizeof(flag));
for(i=1; i<=n; ++i)
scanf("%d",&w[i]);
for(i=1; i<=n; ++i)
scanf("%d",&c[i]);
for(i=1; i<=n; ++i)//时间空间复杂度均为O(VN)
for(j=0; j<=v; ++j)
{
dp[i][j] = dp[i-1][j];
if(j>=c[i])
dp[i][j] = max(dp[i][j],dp[i-1][j-c[i]]+w[i]);
}
for(i=1; i<=n; ++i)
for(j=v; j>=0; --j)
{
if(j>=c[i])
dp2[j] = max(dp2[j],dp2[j-c[i]]+w[i]);
}
printf("%d\n",dp
[v]);
printf("%d\n",dp2[v]);
/*时间复杂度不能优化了,但是空间可以优化到O(V)
for(i=1; i<=n; ++i)
for(j=v; j>=0; --j)//将循环改为这样也是成立的
那么每一个dp[i][j] 都是继承自上一层的dp[i-1][j] 或者dp[i-1][j-c[i]]
那么j是大于等于j或者j-c[i]的。
那么就可以这样
for(i=1; i<=n; ++i)
for(j=v; j>=c[i]; --j)//必须是从后忘前
{
dp2[j] = max(dp2[j],dp[j-c[i]+w[i]]);//这一层继承继承自上一层,这种数组叫做滚动数组
}
*/
//下面是判断哪几个背包被选
int Max = dp
[v];
for(i=n; i>=1; --i)
{
if(dp[i-1][v]>= Max)
flag[i] = false;
else
{
flag[i] = true;
v -= c[i];
Max -= w[i];
}
}
if(flag[1])
printf("1");
else
printf("0");
for(i=2; i<=n; ++i)
if(flag[i])
printf(" 1");
else
printf(" 0");
printf("\n");
}
return 0;
}
/*
5 10
6 3 5 4 6
2 2 6 5 4
Sample Output:
15
1 1 0 0 1
*/
/*
另外还有就是求背包的最优解过程中,有两种要求:
(1)要求背包装满,且价值最大(所以可能导致无解的情况发生)
(2)只要求价值最大
这两种问法差别在于初始化
(1)将dp[0][0]初始化为0,其他的初始化为-INF,这是由题目的性质导致的
初始的时候什么都不装,但是背包有容量而没装满是不合法的,所以定义-INF为不合法的
如果要求背包装满,那么dp[i][j]表示的含义就变为了前i个物品装满容量为j的背包的最大价值
dp[i][j] = max(dp[i-1][j],dp[i-1][j-c[i]]+w[i]);
如果dp[i-1][j],dp[i-1][j-c[i]]+w[i] ,这两个状态是不合法的,那么dp[i][j]也是不合法的
(2)都初始化为0

*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: