0-1背包问题:
- 题目:
有一个背包,它的容量为C(capacity)。现在有n种不同的物品,编号为0…n-1,其中每一件物品的重量为W(i),价值为v(i)。问可以向这个背包中盛放哪些物品,使得在不超过背包容量的基础上,物品的总价值最大。有一个背包,它的容量为C(capacity)。现在有n种不同的物品,编号为0…n-1,其中每一件物品的重量为W(i),价值为v(i)。问可以向这个背包中盛放哪些物品,使得在不超过背包容量的基础上,物品的总价值最大。 - 思路:
暴力解法:每一件物品都可以放进背包,也可以不放进背包。时间复杂度为O((2^n)*n)
贪心算法:优先放入平均价值最高的物品。现实中可以,实际中可能不是最优。贪心算法不能解决0-1背包问题。
动态规划:
F(n,C)考虑将n个物品放进容量为C的背包,使得价值最大。
F(i,c)=max(F(i-1,c)不放,v(i)+F(i-1,c-w(i))放进)
代码:
递归求解:
class Knapsack01{
public:
int knapsack01(const vector<int>& w,const vector<int>& v,int C){
int n=w.size();
return bestValue(w,v,n-1,C);
}
private:
//用[0...index]的物品,填充容积为c的背包的最大价值
int bestValue(const vector<int>& w,const vector<int>& v,int index,int c){
if(index<0||c<=0)
return 0;
int res=bestValue(w,v,index-1,c); //不选index
if(c>=w[index])
res=max(res,v[index]+bestValue(w,v,index,c-v[index]));
return res;
}
};
自顶向下记忆化搜索:
class Knapsack01{
public:
int knapsack01(const vector<int>& w,const vector<int>& v,int C){
int n=w.size();
memo=vector<vector<int>>(n,vector<int>(C+1,-1));
return bestValue(w,v,n-1,C);
}
private:
vector<vector<int>> memo;
//用[0...index]的物品,填充容积为c的背包的最大价值
int bestValue(const vector<int>& w,const vector<int>& v,int index,int c){
if(index<0||c<=0)
return 0;
if(memo[index][c]!=-1)
return memo[index][c];
int res=bestValue(w,v,index-1,c); //不选index
if(c>=w[index])
res=max(res,v[index]+bestValue(w,v,index,c-v[index]));
memo[index][c]=res;
return res;
}
};
动态规划,二维数组
时间复杂度:O(nC)
空间复杂度:O(nC)
class Knapsack01{
public:
int knapsack01(const vector<int>& w,const vector<int>& v,int C){
assert(w.size()==v.size());
int n=w.size();
if(n==0)
return 0;
vector<vector<int>> dp(n,vector<int>(C+1,-1));
//初始化只加入第一个物品
for(int j=0;i<=C;j++)
dp[0][j]=(j>=w[0]?v[0]:0);
for(int i=1;i<n;i++)
for(int j=0;j<=C;j++){
dp[i][j]=dp[i-1][j];
if(j>=w[i])
dp[i][j]=max(dp[i][j],v[i]+dp[i-1][j-v[i]]);
}
return dp[n-1][C];
}
};
动态规划方法的优化:
空间复杂度读为:O(2C)
代码:
class Knapsack01{
public:
int knapsack01(const vector<int>& w,const vector<int>& v,int C){
assert(w.size()==v.size());
int n=w.size();
if(n==0)
return 0;
vector<vector<int>> dp(2,vector<int>(C+1,-1));
//初始化只加入第一个物品
for(int j=0;i<=C;j++)
dp[0][j]=(j>=w[0]?v[0]:0);
for(int i=1;i<n;i++)
for(int j=0;j<=C;j++){
dp[i%2][j]=dp[(i-1)%2][j];
if(j>=w[i])
dp[i%2][j]=max(dp[i%2][j],v[i]+dp[(i-1)%2][j-v[i]]);
}
return dp[n-1][C];
}
};