01背包问题简单描述:
有一个背包和n个物品,背包的承载量为C,每件物品重量为w[i],价值为v[i].问如何装才能使背包中物品的总价值最大?
解题方法:
f[i,j]:在前i个物品中选择若干件放在承重为j的背包中,可以取得的最大的价值。
f[i,j]=MAX(f[i-1,j-w[i]]+v[i] , f[i-1,j]);
决策:为了总价值最大化,第i件物品应该放入背包中吗?
int i,j,C=10;
int p[20][20];
for(i=0;i<=C;i++)
p[0][i]=0;
for(i=1;i<=n;i++)
{
p[i][0]=0;
for(j=1;j<=C;j++)
{
if(j>=w[i])
{
if(p[i-1][j-w[i]]+v[i]>p[i-1][j])
p[i][j]=p[i-1][j-w[i]]+v[i];
else
p[i][j]=p[i-1][j];
}
else
p[i][j]=p[i-1][j];
}
}
问题能深入:如何记录哪些物品被选中了?
void output_sack(int p[20][20],int x[50],int w[50],int n,int C)
{
for(int k=n;k>=2;k--)
{
if(p[k][C]==p[k-1][C];
x[k]=0;
else
{
x[k]=1;
C=C-w[k];
}
}
x[1]=p[[1][C]?1:0;
}
解析:如果物品i没有未选中则:p[i][j]=p[i-1][j]; 所以当p[i][j]==p[i-1][j]是说明第i个物品未被选中。当第i个物品选中后,C=C-w[i],说明第i个已经确定了(背包空间考虑范围减少w[i])。
优化(从二维数组到一维数组)
因为:f[i][j]取决于f[i-1][j]和f[i-1][j-w[i]]+v[i];
所以:f_i[j]取决于f_i-1[j]和f_i-1[j-w[i]]+v[i];(f[j]外套一个for(i=1;i<=n;i++))
所以:可以用滚动的一维数组;
for(int j=0;j<=C;j++)
f[j]=0;
for(i=1;i<=n;i++)
{
for(j=C;j>=w[i];j--)
{
if(f[j-w[i]]+v[i]>f[j])
f[j]=f[j-w[i]]+v[i];
}
}
注意:由于f[j]有f[j]和f[j-w[i]]决定,即在二维数组中的头顶的一个数和左边的一个数决定。所以要由C->0(确保左边的一个数是上一次循环的,即只能取一次),如果由0->C,左边的值可能被改变了。
关于初始化的细节问题
没有要求必须装满:初始化f[j]=0;
要求必须装满:初始化f[0]=0,f[j]=负无穷(j>=1)