本解法的价值矩阵生成由上到下,行表示不同的物品编号,第i行表示有i-1种物品;列表示重量限制。r[i][j]表示仅有i-1号物品时,重量限制为j时,可以得到的最大价值。
价值矩阵r[i][j],i是物品的编号,j是背包的重量限制;物品编号矩阵p[i][j],表示达到价值r[i][j]时,背包里的物品最大编号。可以通过p[i][j] - p[i][ j - w[i - 1]]得到除去该最大编号物品后,物品第二大的编号,以此类推得到全部物品的清单。
r的生成是从上到下的,r[i][j] = max( r[i - 1][j], r[i][j - w[i - 1]] + v[i - 1] )。前一个是不加入节点i,则价值与只有i-1个节点,重量限制为j的价值相同。后一个是加入一个节点i,则价值为本行去除节点i的重量后,重量限制j-w[i]对应的价值,加上节点i能带来的价值v[i-1]。
下方大篇幅为完全背包代码。
若0-1背包有以下区别。
区别1 初始化时:
r[1][i] = i / w[0] * v[0]; ---> if(i<w[0]) r[1][i] = 0; else r[1][i] = v[0];区别2 决定是否加入物品i时:
if(r[i - 1][j] > v[i - 1] + r[i][j - w[i - 1]]) ---> <pre name="code" class="cpp">if(r[i - 1][j] > v[i - 1] + r[i - 1][j - w[i - 1]])
#include <iostream>
#include <memory.h>
using namespace std;
int main(){
int v[] = {1, 3, 5, 9};
int w[] = {2, 3, 4, 7};
int b = 10;
int n = sizeof(v) / sizeof(v[0]);
int **p = new int* [n + 1];//记录达到当前价值时装入的物品的最大编号,用于确定最后需要如何装入物品来达到最大价值
int **r = new int* [n + 1];//记录动态规划的最大价值
int i, j;
for(i = 0; i < n + 1; i++){//创建二维矩阵,并初始化第一列的值为1
r[i] = new int [b + 1];
p[i] = new int [b + 1];
r[i][0] = 0;
p[i][0] = 0;
}
for(i = 0; i < b + 1; i++){//只装入第一件物品,作为动态规划的起始值
r[0][i] = 0;
r[1][i] = i / w[0] * v[0];
p[0][i] = 0;
if(r[1][i]){//不为0,说明装入了第一件物品
p[1][i] = 1;
}
else{
p[1][i] = 0;
}
}
for(i = 2; i < n + 1; i++){
for(j = 1; j < b + 1; j++){
if(w[i - 1] > j){//当前物品装不进去
r[i][j] = r[i - 1][j];
p[i][j] = p[i - 1][j];
}
else{//能装入当前物品,比较装入该物品(该物品价值 + 去掉该物品重量后,剩余重量所能达到的最大价值)和不装入该物品哪种情况价值更高,选择高的那个
if(r[i - 1][j] > v[i - 1] + r[i][j - w[i - 1]]){//不装入当前物品
r[i][j] = r[i - 1][j];
p[i][j] = p[i - 1][j];
}
else{//装入当前物品
r[i][j] = v[i - 1] + r[i][j - w[i - 1]];
p[i][j] = i;
}
}
}
}
int *o = new int [n];//记录达到最大价值时装入的每一件物品的数量
memset(o, 0, n * sizeof(int));
i = b;//当前背包重量
while(i > 0){
j = p[n][i];
if(j > 0){
o[j - 1]++;
i -= w[j - 1];
}
else{
break;
}
}
cout<<"最大价值:"<<r[n][b]<<endl;
for(i = 0; i < n; i++){
cout<<"物品"<<i + 1<<":"<<o[i]<<"件"<<endl;
}
return 0;
}
浙公网安备 33010602011771号