1 0-1背包问题(腾讯2014年笔试)
“背包题目”的基本描述是:有一个背包,能盛放的物品总重量为S,设有N件物品,其重量分别为w1,w2,…,wn,希望从N件物品中选择若干物品,所选物品的重量之和恰能放进该背包,即所选物品的重量之和即是S。递归和非递归解法都能求得“背包题目”的一组解,试写出“背包题目”的非递归解法。
#include<iostream>
#include<string>
#include<algorithm>
#include<numeric>
#include<fstream>
using namespace std;
#define MAXLEN 20
#define MAXW 100
void Backage(int WN[],int n,int W){ //n件物品的重量已知,选取k个恰好放进容量为W的包里,k的选择方案
bool dp[MAXLEN][MAXW]; //取k个数和为s是否存在
memset(&(dp[0][0]),0,sizeof(dp));
dp[0][0]=true;
ofstream out("1.txt");
for(int k=1;k<=n;k++){//取k个数
for(int k0=k;k0>=1;k0--){
for(int s=1;s<=W;s++){
if(s>=WN[k-1]&&dp[k0-1][s-WN[k-1]])
dp[k0][s]=true;
out<<k0<<","<<s<<" "<<dp[k0][s]<<endl;
}
}
}
int count=0;
for(int i=1;i<=n;i++){
if(dp[i][W]){
count++;
cout<<i<<endl;
}
}
cout<<count<<endl; //标记选取物品的件数
}
int main(){
int WN[]={1,2,3,4,5,6,7};
int W=15;
Backage(WN,7,15);
system("pause");
return 0;
}
网友解答如下(原理相同): 动态规划求一组解,我们用f[i][j]用来表示前i件物品随意选择一些物品能够恰好装满容量为j的背包的可行性=1,不可行则为0;如果j < v[i]:f[i][j] = f[i-1][j] ,表示第i个物品的重量已经超过最大重量j了,则结果变为了前i-1件物品能否恰好装入容量为j的背包的可行性即等于f[i-1][j];
如果j>=v[i],此时就可以选择装或者不装第i件物品了,如果装入,则它的可行性就变为了前i-1前物品是否能恰好装入j-vec[i]容量的背包中可行性了;选择不装,则它的可行性变为了前i-1物品能否恰好装入容量为j的背包中可行性了,两者有一个可行,表明前i件物品就能恰好装入容量为j的背包中。f[i][j] = f[i-1][j]||f[i-1][j-vec[i]]
初始化:f[i][0]=1(i=0,1,2,,..n) 其它的f[i][j]都等于0
找出最终的一组解,用回溯就可以了。如果存在可行解,那么f[n][S]一定为1
void packageInteration(vector<int> vec, int S){
int n = vec.size();
int **f = new int*[n+1];
for(int i = 0; i < n+1; i++){
f[i] = new int[S+1];
memset(f[i], 0, sizeof(f[i])*(S+1));
}
for(int i = 0; i < n+1; i++)
f[i][0] = 1; // 初始化
for(int i = 1; i < n+1; i++){
for(int j = 1; j < S+1; j++){
if(j >= vec[i-1])
f[i][j] = (f[i-1][j] || f[i-1][j-vec[i-1]]);
else
f[i][j] = f[i-1][j];
}
}
// 回溯求结果
int j = S;
for(int i = n; i > 0; i--){
if(j >= vec[i-1]){
if(f[i][j-vec[i-1]] == 1){ // 为1 表示可行
res.push_back(i);
j = j - vec[i-1];
}
}
}
}