说明
假设有一个揹包的负重最多可达8公斤,而希望在揹包中装入负重范围内可得之总价物品,假设是水果好了,水果的编号、单价与重量如下所示:
0 |
李子 |
4KG |
NT$4500
|
1 |
苹果 |
5KG |
NT$5700
|
2 |
橘子 |
2KG |
NT$2250
|
3 |
草莓 |
1KG |
NT$1100
|
4 |
甜瓜 |
6KG |
NT$6700
|
解法
揹包问题是关于最佳化的问题,要解最佳化问题可以使用“动态规划”(Dynamic programming),从空集合开始,每增加一个元素就先求出该阶段的最佳解,直到所有的元素加入至集合中,最后得到的就是最佳解。
以揹包问题为例,我们使用两个阵列value与item,value表示目前的最佳解所得之总价,item表示最后一个放至揹包的水果,假设有负重量 1~8的揹包8个,并对每个揹包求其最佳解。
逐步将水果放入揹包中,并求该阶段的最佳解:
揹包负重 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
value |
0 |
0 |
0 |
4500 |
4500 |
4500 |
4500 |
9000 |
item |
- |
- |
- |
0 |
0 |
0 |
0 |
0 |
揹包负重 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
value |
0 |
0 |
0 |
4500 |
5700 |
5700 |
5700 |
9000 |
item |
- |
- |
- |
0 |
1 |
1 |
1 |
0 |
揹包负重 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
value |
0 |
2250 |
2250 |
4500 |
5700 |
6750 |
7950 |
9000 |
item |
- |
2 |
2 |
0 |
1 |
2 |
2 |
0 |
揹包负重 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
value |
1100 |
2250 |
3350 |
4500 |
5700 |
6800 |
7950 |
9050 |
item |
3 |
2 |
3 |
0 |
1 |
3 |
2 |
3 |
揹包负重 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
value |
1100 |
2250 |
3350 |
4500 |
5700 |
6800 |
7950 |
9050 |
item |
3 |
2 |
3 |
0 |
1 |
3 |
2 |
3 |
由最后一个表格,可以得知在揹包负重8公斤时,最多可以装入9050元的水果,而最后一个装入的水果是3号,也就是草莓,装入了草莓,揹包只能再放入7公斤(8-1)的水果,所以必须看揹包负重7公斤时的最佳解,最后一个放入的是2号,也就是橘子,现在揹包剩下负重量5公斤(7-2),所以看负重5公斤的最佳解,最后放入的是1号,也就是苹果,此时揹包负重量剩下0公斤(5-5),无法再放入水果,所以求出最佳解为放入草莓、橘子与苹果,而总价为9050元。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 1e3;
int v, n;
int value[N],w[N];
int dp[N][N];
int main()
{
cin >> n >> v;
memset(dp, 0, sizeof(dp));
for (int i = 1; i <= n; i++)
cin >>w[i] >>value[i];
for (int i = 1; i <= n; i++)
for (int j = v; j >= w[i]; j--)
dp[i][j] =max(dp[i-1][j], dp[i - 1][j - w[i]] + value[i]);
cout << dp[n][v] << endl;
return 0;
}