背包问题

1.问题描述

假设有n件物品,分别编号为1, 2...n。其中编号为i的物品价值为vi,它的重量为wi。为了简化问题,假定价值和重量都是整数值。现在,假设有一个背包,它能够承载的重量是W。如何往包里装这些物品,使得包里装的物品价值最大化。

 

用数学语言描述问题:




2.问题思路分析

我们知道分治法的核心是可以把问题不断分成更小的、更好解决的子问题,然后解决子问题,子问题再合成原问题。但是分治法如果分的子问题如果不独立的话,会在重复的求解共同的子问题。这个问题需要一种另一种思路-----动态规划



可以假设现在求解出了最优解,是1...k(k<n)个物体,对第i个物体,想象一下,如果说拿掉这个物体,剩下的部分针对W-w[i]是不是最优解?用反证法来证明一下,假设不是最优解,那么肯定存在更优的解,那这个更优的解加上我们拿掉的i物体,能够组成比我们求解出的最优解更优,与我们的假设是相违背的。因此,拿掉i物体,剩下的物体依然是W-w[i]的最优解

在n个物体中,假设c[i][j](表示第i个物体,背包剩j的容量)是前i个物体的最优解,那么对第i+1个物体,只有两种情况;

情况1:拿,那么当前的价值为c[i][j]+v[i+1],达到第i+1的最优解;

情况2:不拿,最优解仍然为c[i][j],达到第i+1的最优解;

背包为空或者物体重量超过背包容量时,效益为0;

公式最终可归纳为:




注:对于初学者来说,一开始可能不好理解,建议看一下youtube上的对0-1背包解释的一个视频Dynamic Programming:0/1 Knapsack Problem



3.实现

/*******************************************
0-1背包问题
作者:Andrewseu
日期:2015/12/11
*******************************************/
#include<iostream>
#include<iomanip>
using namespace std;

int value[100];//benifit
int weight[100];//weight

int c[100][100];

void knapsack(int n,int w){
	for (int i = 1; i <= n; ++i){
		for (int j = 1; j <= w; ++j){
			//若第i个物体加进来不超过背包总重量并且价值比之前大,则改变最优值,否则保持不变
			if (weight[i] <= j && c[i - 1][j-weight[i]] + value[i] > c[i - 1][j])
				c[i][j] = c[i - 1][j-weight[i]] + value[i];
			else
				c[i][j] = c[i-1][j];
		}
	}
}

int main(){
	int n, w;
	cout << "Enter the number and weight:";
	cin >> n >> w;

	for (int i = 1; i <= n; ++i){
		cin >> weight[i]>>value[i];
	}
	knapsack(n,w);
	for (int i = 1; i <= n; ++i){
		for (int j = 1; j <= w; ++j){
			cout << setw(6)<<c[i][j] << " ";
		}
		cout << endl;
	}
	return 0;
}

测试输入:

n=4,W=5,weight{2,3,4,5},benefit{3,7,2,9}

输出:10




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值