01背包问题(中篇)
01背包问题 最优解的回溯(back)
那么通过上一回合的分析,我们知道了,二维数组的dp[amount][capacity]的value就是我们想要的最大背包价值。光是知道这么value是不够的,我们还行知道它是由哪些编号的物品组成的,how to solve this issue 呢。首先,我们就得对这dp图的存储理清楚,dp[i][j]这个空里的value是怎么得来的:如果if w[i](放入的物品重量)>j(当前设定的背包容量),那么 此时的dp[i][j] = dp[i-1][j],说明dp[i][j] 与上面dp[i-1][j]的值一样,这个物品i没有放进去。,如果j < w[i],dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i]] + v[i]); 换句话说,要是dp[i][j]!=dp[i-1][j],就说明物品i放进背包中了。好,我们知道了dp[amount][capacity]的location了,是不是就可以开始递归回溯(back)了呢?这回溯的过程中,再判断dp[i][j]是否等于dp[i-1][j],来对i进行标记了。key point:如果当前的i的确放入了背包中,那么 我们就应该回溯到dp[i-1][j-w[i]] 这个位置。
// 01 Backpack Problem
//i(物品编号) 1 2 3 4
//w(体积) 2 3 4 5
//v(价值) 3 4 5 6
#include<iostream>
using namespace std;
const int N=15;
const int amount = 4;
const int capacity = 8;
int w[5] = {0,2,3,4,5};
int v[5] = {0,3,4,5,6};
int dp[N][N] = {{0}};
int temp[amount+1]={0};
void theBack(int i, int j) {
if (i >= 0) {
if (dp[i][j]==dp[i-1][j]) { //说明当前的物品i并没有在最优解中,向上退一步,继续回溯 。
temp[i] = 0;
theBack(i - 1, j);
}
else if (j-w[i] >= 0 &&dp[i][j] == dp[i-1][j-w[i]]+v[i]) { //将物品i记录在temp中,并跳转至添加物品前的上一个最优解位置
temp[i] = 1;
theBack(i-1, j-w[i]);
}
}
}
int main(){
for(int i =1;i<5; i++ ){
for(int j = 1; j < capacity+1;j++){
if(j < w[i])
dp[i][j] = dp[i-1][j];
else{
dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i]] + v[i]);
}
}
}
for (int i=0; i <5; i++) {
for (int j=0; j < capacity+1; j++) {
cout << dp[i][j] << ' ';
}
cout << endl;
}
cout<<dp[amount][capacity];
theBack(amount,capacity);
cout<<endl<<"The optimal solution is:";
for (int i=0; i < amount+1; i++){
if(temp[i]!=0)
cout<<i<<" ";
}
return 0;
}
解决完最优解问题后,我们再思考思考,这是个二维数组,数组空间中还有很大一部分data不是我们想要的(或是意义不大的),那一维数组能够实现数据的动态存储吗…