01背包问题讲解

01背包问题原理细节讲解

1. 什么是01背包问题?
有n个物品,它们有各自的体积和价值,现有给定容量的背包,如何让背包里装入的物品具备最大的价值总和?
为了方便后面的讲解,咱们先用具体的数字来表示物品个数,背包容量,以及对应的每一个物品的体积以及价值,以下表所示:ios


2.01背包问题的解决思路以及原理?web

根据动态规划解题步骤(问题抽象化、创建模型、寻找约束条件、判断是否知足最优性原理、找大问题与小问题的递推关系式、填表、寻找解组成)找出01背包问题的最优解以及解组成,而后编写代码实现。
动态规划与分治法相似,都是把大问题拆分红小问题,经过寻找大问题与小问题的递推关系,解决一个个小问题,最终达到解决原问题的效果。但不一样的是,分治法在子问题和子子问题等上被重复计算了不少次,而动态规划则具备记忆性,经过填写表把全部已经解决的子问题答案纪录下来,在新问题里须要用到的子问题能够直接提取,避免了重复计算,从而节约了时间,因此在问题知足最优性原理以后,用动态规划解决问题的核心就在于填表,表填写完毕,最优解也就找到。算法

最优性原理是动态规划的基础,最优性原理是指“多阶段决策过程的最优决策序列具备这样的性质:不论初始状态和初始决策如何,对于前面决策所形成的某一状态而言,其后各阶段的决策序列必须构成最优策略.编程

  • 解决思路
    在解决问题以前,为描述方便,首先定义一些变量:Vi表示第 i 个物品的价值,Wi表示第 i 个物品的体积,定义V(i,j):当前背包容量 j,前 i 个物品最佳组合对应的价值
  • a) 当物品备选状况(物品备选状况指:可供选择的物品的集合)一致时,背包容量M越大,那么sum_v必定大于等于原来的值。

b) 背包容量M肯定时,可供选择的物品N越多,那么sum_v必定大于等于原来的值。数组

c) 由a)和b)可得,sum_v的最大值就是当M和N取到最大值时的sum_vsvg

c) 从思路上说,01背包问题有两个维度:背包容量M,和供选择物品数N。编程的本质是实现人类解决现实问题的思路。仔细想一想,若是不借助计算机,你该如何解决这个问题?答案是,例如考虑M=1时,先考虑a可否放入背包,取得最大值,再考虑a和b可否放入背包(a和b都是备选,最终放入背包的多是a,多是b,也多是ab),这时所以与以前只考虑a的状况相比,多了一个b,因此:学习

要先判断b可否单独放进背包:
若是不能,那么备选为a,b时最大值,等于备选只有a时的最大值(由于b是放不进背包的)。
  若是能,即b可以放进去,还有两种可能(即将b放进背包,和不将b放进背包),对这两种可能性,要取最大值:
  最终将b放进去(注:此时物品a是否被放进背包是未知的,缘由是:剩余的背包容量可能不足以放进物品a,即要在剩余可选物品里找出最优解。
  最终没有将b放进去(由于后面可能有比b更合适的物品放进去),此时最大值等于备选只有a时的最大值
  用数学的方式描述上段话:sum_v[i][j]表示将前i件物品列为备选,背包容量为j时,能得到的最大价值;w[i]表示第i件物品的重量,v[i]表示第i件物品的价值
  其中V(i-1,j)表示不装,V(i-1,j-w(i))+v(i) 表示装了第i个商品,背包容量减小w(i),但价值增长了v(i);测试

由此能够得出递推关系式:spa

j<w(i) V(i,j)=V(i-1,j)
j>=w(i) V(i,j)=max{V(i-1,j),V(i-1,j-w(i))+v(i)}

这里若是第i件物品的体积大于当前状态的背包总容量,那么第i件物品确定是放不进去的,这个好理解,关键就是第二个式子,不少人看的很懵,心想,若是第i件物品能够装进去,那么为何还要比较和不装这个物品时背包的价值,这个也好理解,就是若是你把第i件物品若是装进去了,可是它是体积大价值小的物品,势必会影响背包的容量以及背包的最大价值,若是不装第i件物品,那么背包的价值就是上一个状态的最优解,即就是上一个状态的背包最大价值,一会我会在表格中详述并举例子说明。
其实,01背包问题的解决过程就是填表的过程,表填完了,最优解也就找到了,在表格的右下角。

在这里插入图片描述
针对刚才上面的疑问,咱们看这个表格来作理解
sum_v[3][7]表示当前有三个物品待装入背包,当前状态的背包容量为7,求此时的背包最大价值。
首先这三件物品的体积都是小于当前背包的状态容量7,若是不装入第三件物品,背包的最大价值为
sum_v[2][7],在表格中查找可得sum_v[2][7] = 9(注意下标从0开始),若是装入第三件物品,背包的最大价值为sum_v[2][7 - 6] + 5 = 0 + 5 <9,也就是说若是把第三件物品装进去,当前背包状态的最大价值反而小了,所以须要取装入和不装入价值的最大做为当前背包状态的最大价值,不能一股脑装进去。
3d

3.C++代码实现01背包问题

#include <iostream>
#include <algorithm>
#include <string>
#include <vector>

using namespace std;

void knapsack(int products_count, int capacity, vector<int> &weight_array, vector<int> &value_array, vector<vector<int>> &result)
{
	for (int i = 1; i <= products_count; ++i)
	{
		for (int j = 1; j <= capacity; ++j)
		{
			//当前背包的容量j放不下第i件物品时
			if (weight_array[i] > j)
			{
				result[i][j] = result[i - 1][j];//放弃第i件物品,拿第i - 1件商品
			}
			else
			{
				result[i][j] = max(result[i - 1][j], result[i - 1][j - weight_array[i]] + value_array[i]);
			}
		}
	}
}
int main()
{
	while (1)
	{
		int products_cout, capacity;
		vector<int> weight_array(1, 0);
		vector<int> value_array(1, 0);
		cout << "please input products count and knapsack's capacity:" << endl;
		cin >> products_cout >> capacity;
		cout << "please input weight array for" << products_cout << "products" << endl;
		//循环输入每件商品的重量
		for (int i = 1; i <= products_cout; ++i)
		{
			int tmp;
			cin >> tmp;
			weight_array.push_back(tmp);
		}
		cout << "please input value array for" << products_cout << "products" << endl;
		//循环输入每件商品的价格
		for (int i = 1; i <= products_cout; ++i)
		{
			int tmp;
			cin >> tmp;
			value_array.push_back(tmp);
		}
		//结果数组
		vector<vector<int>> result(products_cout + 1, vector<int>(capacity + 1, 0));
		//调用动态规划算法
		knapsack(products_cout, capacity, weight_array, value_array, result);
		cout << "knapsack result is " << result[products_cout][capacity] << endl;
		cout << "---------------------------------------" << endl;
		for (int i = 0; i <= products_cout; ++i)
		{
			for (int j = 0; j <= capacity; ++j)
			{
				cout << result[i][j] << "   ";
			}
			cout << endl;
		}


	}
	system("pause");
	return 0;
}

输入当前测试用例的输出为:
在这里插入图片描述 好了,01背包问题的动态规划思路的原理就到此结束了,但愿对你们的学习和理解有所帮助!