C语言动态规划法解决0/1背包问题(详细解答)

动态规划法解决0/1背包问题(详细解答)

首先让我们回顾一下动态规划法的使用规则:

  • 一.、动态规划法的实现思路:

1、划分子问题:将元问题分解为若干个子问题,每一个子问题对应一个决策,并且子问题之间具有重叠关系
2、确定动态规划函数:根据子问题之间的重叠关系找到子问题满足的递归关系式(即动态规划函数),这是实现思路的关键。
3、填写表格:设计表格,自下而上的方式计算各个子问题的解并填表,实现动态规划过程。

  • 二、0/1背包问题

给定n中物品和一个背包,物品i(1<=i<=n)的重量是wi,其价值为vi,背包容量为C,对每种物品只有两种选择:装入背包或不装入背包,如何选择装入背包的物品,是的装入背包的总价值最大?

解题思路:

  1. 我们设V(i,j):表示前 i 个物品中某些物品第 i 个物品放入容量为 j 的背包(书上的解释是:将前 i 个物品装入容量为 j 背包中(当然也包括第 i 个)),我认为书上的这种解释有待商榷,因为前 i 个物品不都会装入!!
  2. 这时候要考虑四个问题:
    1.能装入(背包容量足够)
    2.能装入的情况下:装入
    3.能装入的情况下:不装入
    4.不能装入(背包容量不够)

是不是有点绕,来解释一波:

1、背包容量不足:当我们背包的容量不够的情况下,肯定是不能装入的,这思路很清晰,所以这个时候表示V(i,j)的价值和V(i-1,j)的价值一样,因为第 i 个没有放入。
2、背包容量足够:这时候肯定有人要问了,既然背包容量都足够放第 i 个,为啥不放进去呢?还会有不放入的情况呢?只要是放入价值肯定更大啊?我的解释:当我们将第 i 物品装入不一定达到当前最优解,应当在即V(i,j)=max{V(i-1,j),V(i-1,j-w(i))+v(i)}中选出最优的解!如果前者更大:表示这第 i 个物品没有加入,如果后者更大:表示装入了第 i 个!

2、如果还没有理解透彻,我这有一个栗子:假设我们以能装就装的原则,你可能会装的很满,那如果我最后一个物品重量为2,价值一个亿!!!,那你前面都装了,就装不下这一个亿的价值的东西了,因为我们前面所做的一切操作要考虑会面的情况,并不是找局部的最优解,而是整体考虑填表去寻找整体的最优解,因为局部的最优加起来不能代表全体的最优!

3、我们加速,列出动态函数:

V(i,j)=V(i-1,j) j<wi ;(装不下)
V(i,j)=max{ V(i-1,j),V(i-1,j-wi)+vi } j>=wi ;(能装下,前者不装,后者装)

4、ok我们开始列出我们另一个函数:关于物品取与不取的关系Xi:

Xi=0;表示第 i 个物品没有放入 V(i,j)= V(i-1,j)
Xi=1;表示第 i 个物品放入 V(i,j)> V(i-1,j) 或 V(i,j)= V(i-1,j-wi)+vi

**5、**列出动态规划表格

我们假设有5个物品,重量w{2,3,4,5}, 价值v{3,4,5,6},背包容量为8.

1.首先边界初始化:V(0,j)= V(i,0)=0
在这里插入图片描述
2.
如,i=1,j=1,w(1)=2,v(1)=3,有j<w(1),故V(1,1)=V(1-1,1)=0;
又如i=1,j=2,w(1)=2,v(1)=3,有j=w(1),故V(1,2)=max{ V(1-1,2),V(1-1,2-w(1))+v(1) }=max{0,0+3}=3;
如此下去,填到最后一个,i=4,j=8,w(4)=5,v(4)=6,有j>w(4),故V(4,8)=max{ V(4-1,8),V(4-1,8-w(4))+v(4) }=max{9,4+6}=10……
在这里插入图片描述
最终答案:V(4,8)=10;

代码实现

int KnapSack(int w[],int v[],int n,int C)
{
	int i,j;
	for(i=0;i<=n;i++)
	{
		v[i][0]=0;
	}
	for(j=1;j<=c;j++)
	{
		v[0][j]=0;
	}
	for(i=1;i<=n;i++)
	{
		for(j=0;j<=c;j++)
		{
			if(j<w[i])
			{	
				v[i][j]=v[i-1][j];
			}
			else{
				v[i][j]=max(v[i-1][j],v[i-1][j-w[i]]+v[i]);
			}
	}
	for(j=c,i=n;i>0;i--)
	{
		if(v[i][j]>v[i-1][j])
		{
			x[i]=1;
			j=j-w[i];
		}
		else x[i]=0;
	}
	return v[n][c];
}


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小司卫理理参上

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值