您的位置:首页 > 其它

背包问题

2015-12-11 21:54 232 查看

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

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: