背包问题

来源:互联网 发布:网络主播 无聊 编辑:程序博客网 时间:2024/06/05 06:59

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];//benifitint weight[100];//weightint 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];elsec[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 0
原创粉丝点击