问题简介

输入:n种物品和一个背包

物品i的重量是wi,价值为vi

背包的容量是C

输出:装入背包的物品

优化目标是:装入背包的物品总价值最大

优化子结构

设(x1,x2,x3…xn)是0-1背包问题的一个最优解。

如果x1=1,那么(x2,x3,x4,x5…xn)是以下子问题的最优解:
在这里插入图片描述
如果x1 =0:则 (x2, …, xn) 是以下子问题的最优解
在这里插入图片描述

递归关系

设m(i, j)为背包问题的最优值,这里背包容量为j,可选物品为i, i+1, …, n,

有如下递归关系:

如果i<n时
在这里插入图片描述

i=n时

在这里插入图片描述

优化子结构

在这里插入图片描述

表格举例

给出如下三个物品,背包容量为5:
在这里插入图片描述

构造下列表格:
在这里插入图片描述
其中m[i][j]表示放入0-i的物品,背包容量为j的价值。

现在考虑放入id为0的物品,因为物品重量为1,所以在背包容量为0时无法放入,其他情况下都可以放入物品0,所以表格变为:
在这里插入图片描述
第二行时,要考虑放入0,1两个物品了,所以需要用到我们的迭代公式,

例如m[1][0],此时的背包容量为0,则什么都放不下为0,

而m[1][1]时,j<w1(物品1的重量为2),所以此时m[1][1]=m[0][1]=6;

再例如m[1][2]时,j>w1,此时m[1][2]=max{m[0][2],m[0][0]+v2}=max{6,0+10}=10

按照这个理论挨个填写,得到结果如下:

在这里插入图片描述
此时的m[2][5]是最佳的价值,但是如何求出最优解呢?

我们回顾m[2][5]的得到过程,m[2][5]=m[1][2]+v2=m[0][0]+v1=v1+v2,因此最佳解为放入物品1和物品2。

具体在算法中如何实现呢?我们选择利用上述的二维数组进行逆推,从最大可装入价值处逆推。

最大可装入价值处容量为5,减去最后放入的物品2的重量,得到5-3=2,我们跳转到去掉物品2,容量为2处,也就是m[1][2]处,此时装入了物品1,而1的重量为2,去掉物品1,和容量2,剩下m[0][0],此时容量已经变为0,算法结束,也就是装入了物品1和物品2。

具体代码如下:

#include<iostream>
#include<stdio.h>
#define N 6		//物品的个数
#define W 21	//背包容量

int B[N][W] = { 0 };
int w[6] = { 0,2,3,4,5,9 };	//物品重量
int v[6] = { 0,3,4,5,8,10 };//物品价值

void knapsack()
{
	int k;	//第K个物品
	int C;	//背包剩余重量

	//填表
	for (k = 1; k < N; k++)
	{
		for (C = 1; C < W; C++)
		{
			if (w[k] > C)								//第k件物品放不进去 此时背包的价值 = 判断完上一件物品之后背包的价值
			{
				B[k][C] = B[k - 1][C];
			}
			else
			{
				int value1 = B[k - 1][C - w[k]] + v[k];	//放入第k件物品后 背包总价值 = 先给这件物品留出空间,剩余的背包大小能装进的最大价值 + 这件物品的价值
				int value2 = B[k - 1][C];				//不放入第k件物品 背包总价值 = 不用给这件物品留出空间,当前背包大小能装进的最大价值(就是判断完上一件物品之后背包的价值)

				if (value1 > value2)
				{
					B[k][C] = value1;
				}
				else
				{
					B[k][C] = value2;
					if (value1 < value2)printf("k=%d C=%d\n", k, C);
				}
			}
		}
	}
}
int main()
{
	knapsack();
	for (int i = 0; i < N; i++)
	{
		for (int j = 0; j < W; j++)
		{
			printf("%4d ", B[i][j]);
		}
		printf("\n\n");
	}
	system("pause");
}

(代码摘自:https://hanquan.blog.csdn.net/article/details/89456491)

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐