动态规划——01背包问题

泄露秘密 提交于 2019-11-26 16:54:37

01背包问题

背包问题是著名的NP完全问题,在实际生活中有广泛的应用。01背包是背包问题中的一种,也是较简单的一种,利用动态规划的思想可以寻求01背包的解。

问题描述

设有n个物品,他们具有各自的重量w和价值v;给定一个具有一个容量W的背包,求将物品有选择的放入背包中,使得装入的物品的价值之和最大?

01背包:物品是完整个体,只存在放或不放两种状态,不能放入一部分。

分析设计

动态规划求解问题需要找到可分解的大问题,将问题不断划分为子问题就可以求解,通过一个二维数组构成的表的形式记录子问题,最终大问题的解也可以求解出来。

01背包问题中的子问题是什么?

  • 更少的物品:当只有0件物品时,答案就很明显了,不用放;
  • 更小的背包:当背包的容量为0时,答案就很明显了,放不了。

因此构建二维数组K(n,W)K(n,W),其中K(i,j)K(i,j)表示:当前背包容量为j,物品有前i个可以放,此时的背包问题的。

只要我们能找到一个递推关系,能使我们从K(0,0)K(0,0)算到K(n,W)K(n,W)即可,K(n,W)K(n,W)就是整个大问题的解。

对于求K(i,j)K(i,j),当前商品存在了两种可能:

  • 新的物品i加进来,背包放不下,即第i件物品在背包容量为k的情况下不放入背包——K(i,j)=K(i1,j)K(i,j)=K(i-1,j)
  • 新的物品i加进来,背包能放下,但装了也不一定能达到更优的值,还是需要选择第i件物品装与不装——K(i,j)=max[K(i1,j),K(i1,jwi)+vi]K(i,j)=max[K(i-1,j),K(i-1,j-w_i)+v_i]

最后,就是对表的初始化了,上面已经讨论过了,当没有物品时,当背包容量为0时,即K(i,0)=K(0,j)=0K(i,0)=K(0,j)=0

运用动态规划的思想解01背包问题的时间复杂度为O(nW)

源代码

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

//物品类型
struct goods{
	int weight;		//物品重量
	int value;		//物品价值
};

//非递归解法
int Knapsack(goods g[],int number,int capacity){
	vector<vector<int> > k(number + 1, vector<int>(capacity + 1));		//初始化记录数组
	for (int i = 0; i < number; i++)
		k[i][0] = 0;
	for (int i = 0; i < capacity; i++)
		k[0][i] = 0;

	for (int i = 1; i <= number; i++) {
		for (int j = 1; j <= capacity; j++) {
			if (j < g[i - 1].weight)
				k[i][j] = k[i - 1][j];	//放不下
			else
				k[i][j] = max(k[i - 1][j], k[i - 1][j - g[i-1].weight] + g[i-1].value);	//放得下,进行比较
		}
	}

	return k[number][capacity];
}

//递归解法
int MFKnapsack(goods g[], int number, int capacity) {
	vector<vector<int> > k(number + 1, vector<int>(capacity + 1));		//初始化记录数组
	for (int i = 0; i <= number; i++)
		for (int j = 0; j <= capacity; j++)
			k[i][j] = -1;
	for (int i = 0; i < number; i++)
		k[i][0] = 0;
	for (int i = 0; i < capacity; i++)
		k[0][i] = 0;

	if (k[number][capacity] < 0) {
		int value;
		if (capacity < g[number - 1].weight)
			value = MFKnapsack(g, number - 1, capacity);	//放不下
		else
			value = max(MFKnapsack(g, number - 1, capacity), MFKnapsack(g, number - 1, capacity - g[number].weight) + g[number].value);	//放得下,进行比较
		k[number][capacity] = value;
	}
	return k[number][capacity];
}

int main() {
	int capacity, number;
	cout << "输入背包容量:";
	cin >> capacity;
	cout << "输入物品个数:";
	cin >> number;
	goods *g = new goods[number];
	cout << "输入物品信息:(重量w 价值v)" << endl;
	for (int i = 0; i < number; i++)
		cin >> g[i].weight >> g[i].value;
	
	cout << "背包最大价值为:";
	cout<<Knapsack(g,number,capacity)<<endl;			//非递归
	//cout << MFKnapsack(g, number, capacity) << endl;	//递归
	
	delete []g;
	system("pause");
	return 0;

}

运行结果

在这里插入图片描述

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!