01背包问题(51nod-1085)
问题来源:51nod
总容量W,N件物品体积分别为W1,…Wn(整数),价值分别为P1,…,Pn(整数),求背包能容纳的最大价值。
该问题属于动态规划问题。设当总容量不超过w,考虑前k件物品时的最大价值为p(k,w)。则p(k,w)满足
1. p(k,0)=0
2. p(0,w)=0
3. p(k,w)=p(k-1,w), Wk>w
4. p(k,w)=max(p(k-1,w),p(k-1,w-Wk)+Pk)
条件4的含义为k,w的最优情况分两部分考虑,第一部分是最优情况中不包含物品k,等价于k-1,w的最优情况,第二部分是最优情况中包含物品k,等价于k-1,w-Wk的最优情况+Pk。
为避免递归带来的许多重复运算,可以使用二维数组保存p(k,w),由于k的情况依赖于k-1的情况,所以从k=0更新至k=N,直到得到p(N,W)。
#include <iostream>
using namespace std;
void PackageTable(int N, int W, int* w, int* p, int** table, int** road) {
for (int i = 0; i <= N; ++i) {
table[i][0] = 0;
}
for (int i = 0; i <= W; ++i) {
table[0][i] = 0;
}
for (int i = 1; i <= N; ++i) {
for (int j = 1; j <= W; ++j) {
int value1 = table[i - 1][j];
if (w[i-1] <= j) {
int value2 = table[i - 1][j - w[i-1]] + p[i-1];
if (value1 > value2) {
table[i][j] = value1;
road[i][j] = 0;
}
else {
table[i][j] = value2;
road[i][j] = 1;
}
}
else {
table[i][j] = value1;
road[i][j] = 0;
}
}
}
}
void PackageRoad(int i, int j, int* w, int* p, int** table, int** road) {
if (i && j) {
if (road[i][j] == 1) {
PackageRoad(i - 1, j - w[i-1], w, p, table, road);
cout << i << " ";
}
else {
PackageRoad(i - 1, j, w, p, table, road);
}
}
}
int main() {
int N, W;
cin >> N >> W;
int *w = new int[N];
int *p = new int[N];
for (int i = 0; i < N;++i) {
cin >> w[i] >> p[i];
}
int **table = new int*[N + 1];
for (int i = 0; i <= N; ++i) {
table[i] = new int[W + 1];
}
int **road = new int*[N + 1];
for (int i = 0; i <= N; ++i) {
road[i] = new int[W + 1];
}
PackageTable(N, W, w, p, table, road);
//PackageRoad(N, W, w, p, table, road);
cout << table[N][W] << endl;
delete[] w;
delete[] p;
for (int i = 0; i <= N; ++i) {
delete[] table[i];
delete[] road[i];
}
delete[] table;
delete[] road;
}