您的位置:首页 > 其它

01背包问题

2008-12-05 17:22 387 查看
背包九讲:http://leafduo.com/oi/dd-pack/
分别运用递归,空间O(n*v)的递推和空间O(v)的递推解决01背包.

bag:运用递归,状态为bag(int n, int v),即前n件物品恰放入一个容量为v的背包可以获得的最大价值。写出状态转移方程:bag(n, v)=max(bag(n-1, v-cost
)+weight
, bag(n-1, v))
。终止条件为1. 背包容量小于零时(v<0)返回无穷小,因为是不可能发生的;2. 递归到第一个物品且此时背包容量小于第一个物品的重量(n==1 && v<cost[1]),返回零;3.递归到第一个物品且此时背包容量大于等于第一个物品的重量(n==1 && v>=cost[1]),返回第一个物品的价值(weight)。

bag2运用空间度O(n*v)的递推。首先初始化,将数组f[][]成员全部置零。然后自底向上递推, 推f
[v]时需要知道f[n-1][v-cost
]和f[n-1][v]两个值。其中需要考虑v-cost
小于零的情况:v-cost
小于零时f
[v]=f[n-1][v](因为bag(n, 负数)==负无穷大)。

bag3将bag2的空间优化到O(v)。即只需要一维数组f2[]。所以每次递推n时需要覆盖原来f2中的数据。f2[v]=max(f2[v-cost
]+weight
, f2[v])
。因为f2[v]需要知道f2[v-cost
的值,所以递推v时必须从后往前(即v=V....0)。此时可以对v的取值范围进行一次优化:当v-cost
小于零时,f2[v]=f2[v],值保持不变,所以可以缩小v的范围至v=V....cost


仔细考虑,还可以对v的范围优化,从最后一个物体向前考虑,因为只要得到最后f2[v]的答案,而f2[v]的答案来自于前一个物品f2[v]与f2[x]+weight
的最大值,所以前一个物品只需从后向前计算到f2[v-weight
]即可停止。以此类推第j个物品需要计算到f2[v-sum(weight[j]....weight
)。此时又需要同cost取max,相见代码:)
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 2000
#define MINIMUM -10000000;
int cost[MAXSIZE];//数组下标从1开始
int weight[MAXSIZE];//数组下标从1开始
int f[200][MAXSIZE];
int f2[MAXSIZE];
int bag(int n, int v)//运用递归
{//前n件物品恰放入一个容量为v的背包可以获得的最大价值
int val=0;
if (v<0)
return MINIMUM;
if (n==1 && v<cost[1])
return 0;
if (n==1 && v>=cost[1])
return weight[1];
val=max(bag(n-1, v-cost
)+weight
, bag(n-1, v));
return val;
}

int bag2(int n, int v)//运用空间复杂度为O(n*v)递推
{
int i, j;
for (i=0; i<=n; i++){//初始化
for (j=0; j<=v; j++){
f[i][j]=0;
}
}
for (i=1; i<=n; i++){
for (j=0; j<=v; j++){
if (j>=cost[i])
f[i][j]=max(f[i-1][j-cost[i]]+weight[i], f[i-1][j]);
else
f[i][j]=f[i-1][j];
}
}
return f
[v];
}

int bag3(int n, int v)//运用空间复杂度为O(n)递推
{
int i, j;
for (i=0; i<=v; i++){//初始化
f2[i]=0;
}
for (i=1; i<=n; i++){
for (j=v; j>=cost[i]; j--){
f2[j]=max(f2[j-cost[i]]+weight[i], f2[j]);
}
}
return f2[v];
}

main(int argc, char *argv)
{
int N, V;
int i, res;
freopen("01.txt", "r", stdin);
while (scanf("%d%d", &V, &N)!=EOF){
for (i=1; i<=N; i++)
scanf("%d%d", &cost[i], &weight[i]);
res=bag(N, V);
printf("%d/n", res);
}
}
再次经过优化的bag3:
int bag3(int n, int v)//运用空间复杂度为O(n)递推
{
int i, j, sum=0, bound;
for (i=0; i<=v; i++){//初始化
f2[i]=0;
}
weight[0]=0;
for (i=1; i<=n; i++){
sum+=weight[i];
}
for (i=1; i<=n; i++){
sum-=weight[i-1];
bound=max(v-sum, cost[i]);
for (j=v; j>=bound; j--){
f2[j]=max(f2[j-cost[i]]+weight[i], f2[j]);
}
}
return f2[v];
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: