详解01背包问题

翻译 2018年04月15日 12:00:16

本篇博客在下面这篇博客的基础上对代码作了一些白话文的注释:

背包问题详解

01背包问题描述:有编号分别为a,b,c,d,e的五件物品,它们的重量分别是2,2,6,5,4,它们的价值分别是6,3,5,4,6,每件物品数量只有一个,现在给你个承重为10的背包,如何让背包里装入的物品具有最大的价值总和?

动态规划的基本思路:将该问题转换成子问题,考虑五件物品在给定承重 C 的背包下最大价值为原问题,如下表所示,即为考虑abcde,C = 10时的最大价值,假设为f[5][10],原问题的解可以分解为两种情况,第一种情况是不考虑放入a只考虑放入bcde承重为C时的最大价值f[4][C],第二种情况是考虑放入a时的最大价值,即value[a]+f[4][10-weight[a]]。 原问题的解f[5][10]取上述两种情况中的最大值,即f[5][10] = max{f[4][10], (f[4][10-weight[a]+value[a]))}。 由此可以看出里面涉及到需要计算f[4][10]和f[4][10-weight[a]]即f[4][4]等子问题。 以此类推,自顶向下的分析可以看出原问题需要子问题的解,我们需要先计算出子问题的解,自底向上求解。求解方式如下表所示,顺序是自底向上、从左往右,或者从左往右、自底向上都可以。注意此问题中的abcde可以包含相同的物件,它们之间的顺序也可以是任意的,不影响最终的结果。

nameweightvalue012345678910
a260066991212151515
b230033669991011
c650000666661011
d540000666661010
e4600006666666

代码如下:

#include<iostream>
using namespace std;

int knapsack(int *W, int *V, int *res, int n, int C);
int Test();
int main() 
{
	Test();
	return 0;
}

//选取方案:自底向上
int knapsack(int *W, int *V, int *res, int n, int C) 
{
	int maxvalue = 0;
	int **f = new int *[n];
	for (int i = 0; i < n; i++) 
	{
		f[i] = new int[C+1];
	}
	//初始化
	for (int i = 0; i < n; i++)
		for (int j = 0; j <= C; j++)
			f[i][j] = 0;
	//当只取第一个石头
	for (int j = 1; j <= C; j++) 
	{
		f[0][j] = (j < W[0]) ? 0 : V[0];
	}
	//当取前(i+1)个石头时
	for (int i = 1; i < n; i++) 
	{
		for (int j = 1; j <= C; j++) 
		{
			if (j >= W[i]) 
			{
				//当遍历到第(i+1)个石头时接着遍历背包重量,如果重量大于第(i+1)个石头重量则判断:
				//不加入第(i+1)个石头背包存储的价值  是否大于 背包减去第(i+1)个石头的重量时的价值+第(i+1)个石头的价值,大于则不放第(i+1)个,小于则可能去掉一些重量可能不去加入第(i+1)个石头
				//什么叫可能去掉,可能不去掉,比如存储了前两个石头重量为2,3且价值为3,4的石头,此时加入第三个石头总量为5,且价值为8的石头,那么就取出了第1,2个石头;
				//若第三个石头重量为3,价值为2,那么第一次j=3时,j-3时3 > (f[2][0]+2)暂时不存入第3个石头.....
				f[i][j] = (f[i - 1][j] > (f[i - 1][j - W[i]] + V[i])) ? f[i - 1][j] : (f[i - 1][j - W[i]] + V[i]);
			}
			else 
			{
				//如果不大于,那么此时遍历背包存储空间时还是存放原来石头,即不加入第(i+1)个石头.
				f[i][j] = f[i - 1][j];
			}
		}
	}

	//选取过程
	for (int i = 0; i < n; i++) 
	{
		for (int j = 0; j <= C; j++)
			cout << f[i][j] << " ";
		cout << endl;
	}

	maxvalue = f[n - 1][C];
	//查找最优解时的选取项
	int i = n - 1;
	int j = C;
	while (i) 
	{
		//因为我们知道f[n-1][C]为最优解,那么下列式子满足则说明选取了第i个石头
		if (f[i][j] == (f[i - 1][j - W[i]] + V[i])) 
		{
			res[i] = 1;
			j = j - W[i];
		}
		--i;
	}
	//别忘了还有第1个石头不知道是否选取
	if (f[0][j]) 
	{
		res[0] = 1;
	}
	
	//删除内存空间
	for (int i = 0; i < n; i++) 
	{
		delete f[i];
		f[i] = 0;
	}
	delete[] f;
	f = 0;
	return maxvalue;
}

int Test(){
	
	int n, C;           //石头的个数以及背包重量
	while (cin >> n >> C) 
	{
		int *W = new int[5];
		int *V = new int[5];
		int *res = new int[5];     //存放石头,1表示取,0表示不取
		for (int i = 0; i < 5; i++) 
		{
			res[i] = 0;
		}
		int w = 0, v = 0, i = 0;
		//输入石头重量
		while (i < n) 
		{
			cin >> w;
			W[i++] = w;
		}
		//输入石头价值
		i = 0;
		while (i < n) 
		{
			cin >> v;
			V[i++] = v;
		}
		int Value = knapsack(W, V, res, n, C);
		cout << "最优解: " << Value <<endl;
		cout << "选取石头方案:";
		for (i = 0; i < 5; i++) 
		{
			cout << res[i] << " ";
		}
		cout << endl;
		delete W;
		delete V;
		delete res;
		return 0;
	}
}

01背包问题吐血详解

背包问题我真是学一次忘一次,很多dp问题也是由这个衍生而来,今天终于痛下决心写个博客供自己日后参考 问题描述: 有N件物品和一个容量为V的背包。第i件物品的费用是c[i],价值是w[i]。求解将哪些物...
  • u013445530
  • u013445530
  • 2014-10-18 13:29:20
  • 7038

最通俗易懂的01背包问题讲解

1、动态规划(DP)  动态规划(Dynamic Programming,DP)与分治区别在于划分的子问题是有重叠的,解过程中对于重叠的部分只要求解一次,记录下结果,其他子问题直接使用即可,减少了重复...
  • FX677588
  • FX677588
  • 2017-04-02 14:02:51
  • 10970

01背包问题总结

总结一下 按照:http://blog.csdn.net/libin56842/article/details/9338841 这个博客 提供的题号(感谢大牛) 和自己多加的几道01背包的题目。其状态...
  • yexiaohhjk
  • yexiaohhjk
  • 2015-12-09 01:08:56
  • 1255

动态规划之01背包问题讲解

给大家附上一个题目吧,便于理解 ctest有n个苹果,要将它放入容量为v的背包。给出第i个苹果的大小和价钱,求出能放入背包的苹果的总价钱最大值。 输入:每组测试数据第一行为2个正整数,...
  • su20145104009
  • su20145104009
  • 2016-05-04 10:21:24
  • 3504

01背包问题详解

首先非常感谢刘汝佳的小白书、HDU刘春英老师的ACM程序设计背包算法课件以及dd_engi的背包九讲和众多大神的博客,看这么多资料最后花了整整一天时间才算大致弄懂了背包问题的思路(=_=搞这么久我确实...
  • qq_33171970
  • qq_33171970
  • 2016-01-25 13:53:03
  • 3540

01背包问题 -- 经典动态规划题

01背包问题 问题描述:有n个重量和价值分别为Wi,Vi的物品,从这些物品中挑选出总重量不超过W的物品,求怎么挑选才能使价值最大; 首先可以使用搜索来看看,吧每件物品放入背包试试,找出最优解。 /...
  • u014235934
  • u014235934
  • 2016-03-16 14:51:46
  • 398

背包问题01图文附带代码,非常清晰

浅谈DP算法(一)                   ——如何用一维数组解决01背包问题     DP算法(Dynamic Programming,俗称动态规划)是最经典算法之一....
  • wbuhuibiandaima
  • wbuhuibiandaima
  • 2017-03-22 18:48:57
  • 2227

总结——01背包问题 (动态规划算法)

0-1 背包问题:给定 n 种物品和一个容量为 C 的背包,物品 i 的重量是 wi,其价值为 vi 。 问:应该如何选择装入背包的物品,使得装入背包中的物品的总价值最大?...
  • xp731574722
  • xp731574722
  • 2017-04-25 20:57:57
  • 23448

背包问题详解:01背包、完全背包、多重背包

参考链接: http://www.cnblogs.com/fengty90/p/3768845.html http://blog.csdn.net/mu399/article/details/7722...
  • na_beginning
  • na_beginning
  • 2017-03-17 11:47:48
  • 14979

动态规划解决01背包问题(java实现)

01背包问题与背包问题的区别在于,01背包,物品的选择只有两种一种是拿,另一种是不拿,而背包问题在于,物品可以只取一部分。所以01背包问题不能用贪心算法解决。 以dp[i][j]表示用i种物品,重量为...
  • qq_22222499
  • qq_22222499
  • 2017-04-30 13:52:12
  • 1930
收藏助手
不良信息举报
您举报文章:详解01背包问题
举报原因:
原因补充:

(最多只允许输入30个字)