0/1背包问题

有n个物品,每个物品重量为wi, 价值为pi, 有装载重量为c的箱子,问如何进行装载是箱子中物品的总价值最大

sum(pi xi), xi为0或者1,0表示不装载此货物,1表示装载次货物,约束条件为sum(wi xi)<=c

复杂度:NP

1. 贪婪的方法是不不能保证最优的

一般有如下三种贪婪方式,a)最大价值 b)最小重量 c)价值重量比 pi/wi

2.递归解法

假设f(i, j)表示1,2,i-1个物品已经选择,剩余载重为j的最优解

int recursiveKnapsack(int i, int y)
{
if(i==n-1)return (y
if(y
return max(recursiveKnapsack(i+1,y), recursiveKnapsack(i+1,y-w[i])+p[i]);
}

这种解法的复杂度很高为2^n, 其实这种方法等同于枚举位长为n的二进制串的所有组合。

3 动态规划方法

此处的想法其实和递归是一样的,只是这里用空间换取时间上的高效了。

设f(i,y)为剩余载重为y,剩余物品为i,i+1,...,n的最优解

则f(i,y)=max(f(i+1,y), f(i+1, y-wi)+pi)  if y>=wi

else f(i,y)=f(i+1,y)

写成程序为

void
DPKnapsack(int dp[][c+1])
{
for (int y = 0; y < w[n-1]; y++)
dp[n-1][y] = 0;
for (int y = w[n-1]; y <= c; y++)
dp[n-1][y] = p[n-1];
for (int i = n - 2; i > 0; i--)
{
for (int y = 0; y < w[i]; y++)
dp[i][y] = dp[i + 1][y];
for (int y = w[i]; y <= c; y++)
dp[i][y] = max(dp[i + 1][y], dp[i + 1][y - w[i]] + p[i]);
}
dp[0][c] = dp[1][c];
if (c >= w[1])
dp[0][c] = max(dp[1][c], dp[1][c - w[1]] + p[0]);
}

注意程序中和表述中的下标差一问题。

此处我们假设问题数据为全局的,比如:

const int n = 3;
const int w[] =
{ 100, 10, 10 };
const int p[] =
{ 20, 15, 15 };
const int c = 105;

这个问题的解为[0 1 1], 最大价值为30.

3. 回溯

backtrackKnapsack(int i, int c, int sump, int& max)
{
if (i >= n)
{
if (sump > max)
max = sump;
return;
}
if (c >= w[i])
backtrackKnapsack(i + 1, c - w[i], sump + p[i], max);
backtrackKnapsack(i + 1, c, sump, max);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值