一、0-1背包
使用O(C)空间复杂度的0-1背包代码:
/*
* 改成一维数组的0-1背包
* n为物品个数,
* C为背包容量
* w为重量数组
* v为价值数组
* 为了显示方便,我们的w和v数组都是以0开头,占用了一个位置
*/
void newknapsack(int n, int C, int w[], int v[])
{
int V[C+1];
for(int i=0; i<C+1; ++i)
V[i] = 0;
for(int i = 1; i <= n; i++)
{
//注意,这里是逆序,为了获取i-1时的V值
for(int j = C; j>=0; --j)
{
//如果放得下
if(j >= w[i])
{
V[j] = (V[j] >= V[j-w[i]]+v[i] ? V[j] : V[j-w[i]]+v[i]);
}
}
/*
for(int j=0; j<=C; ++j)
{
cout<<V[j]<<" ";
}
cout<<endl;
*/
}
printf("the biggest value is %d\n", V[C]);
}
二、完全背包
使用O(C)空间复杂度的完全背包,代码和上面差不多,唯一不同的地方是内层循环j是从小到大。
void newknapsack1(int n, int C, int w[], int v[])
{
int V[C+1];
for(int i=0; i<C+1; ++i)
V[i] = 0;
for(int i = 1; i <= n; i++)
{
//注意,这里是逆序,为了获取i-1时的V值
for(int j = 0; j <= C; ++j)
{
//如果放得下
if(j >= w[i])
{
V[j] = (V[j] >= V[j-w[i]]+v[i] ? V[j] : V[j-w[i]]+v[i]);
}
}
for(int j=0; j<=C; ++j)
{
cout<<V[j]<<" ";
}
cout<<endl;
}
printf("the biggest value is %d\n", V[C]);
}
三、需要注意的一些细节
如果要求背包不是恰好装满,则V[C+1]全部赋值为0就可以;如果要求背包恰好装满,则对于V[C+1]来说,V[0]赋值为0,剩下的都赋值为-INF。例如下面的代码:
void newknapsackk(int n, int C, int w[], int v[])
{
//注意V的初始化
int V[C+1];
V[0] = 0;
for(int i=1; i<C+1; ++i)
V[i] = INT_MIN;
for(int i = 1; i <= n; i++)
{
//注意,这里是逆序,为了获取i-1时的V值
for(int j = C; j>=0; --j)
{
//如果放得下
if(j >= w[i])
{
V[j] = (V[j] >= V[j-w[i]]+v[i] ? V[j] : V[j-w[i]]+v[i]);
}
}
for(int j=0; j<=C; ++j)
{
cout<<V[j]<<" ";
}
cout<<endl;
}
printf("the biggest value is %d\n", V[C]);
}
调用该函数:
int weight[4] = {0, 3, 4, 5};
int value[4] = {0, 4, 5, 6};
newknapsackk(3, 10, weight, value);
计算过程如下:
0 -2147483648 -2147483648 4 -2147483644 -2147483644 -2147483644 -2147483644 -2147483644 -2147483644 -2147483644
0 -2147483648 -2147483648 4 5 -2147483643 -2147483643 9 -2147483639 -2147483639 -2147483639
0 -2147483648 -2147483648 4 5 6 -2147483642 9 10 11 -2147483637
这就要我们能够判断最后结果是否是-INF。
还有一个问题就是输出使用的物品的向量,即0,未使用,1,使用了。还是需要使用O(C*n)的空间复杂度。