背包问题的几种解法及变形
2014-05-15 16:00
429 查看
背包问题
一、01背包
问题描述:
•给定n种物品和一个背包,
物品i的重量是wi, 价值是vi, 背包容量为W
•对于每个物品,要么装背包,要么不装
•选择装背包的物品集合,使得物品总重量不超过背包容量W, 且价值和尽量大
限制条件: 1<=n<=100 1<=wi,vi<=100 1<=W<=10000
输入:
4 5
2 3
1 2
3 4
2 2
输出:
7
i表示物品编号
j表示剩余背包容量
1.首先给出最朴素的方法,针对每个物品是否放入背包进行搜索
时间复杂度:O(2^n)
2.由于上面的方式时间复杂度较大,下面给出了利用记忆数组dp进行优化的方法,把第一次的计算结果记录下来,省掉了以后的计算
dp[i+1][j] = dp[i][j] (j<w[i])
= max(dp[i][j],dp[i][j-w[i]]+v[i]) 其他
二、完全背包
问题描述:
•给定n种物品和一个背包, 物品i的重量是wi, 价值是vi, 背包容量为W
•对于每个物品,要么装背包,要么不装
•选择装背包的物品集合,使得物品总重量不超过背包容量W, 且价值和尽量大
•每种物品可选多件
输入:
3 7
3 4
4
5
2
3
输出:
10
1.一个三层循环的dp,它的时间复杂度是O(nW^2),效率并不高
dp递推式
dp[0][j] = 0
dp[i+1][j] = max(dp[i+1][j], dp[i][j-k*w[i]+k*v[i]) (k*w[i] <= j)
dp[i+1][j] = dp[i][j]
(j < w[i])
=
max(dp[i][j],dp[i+1][j-w[i]]+v[i]) 其他
一、01背包
问题描述:
•给定n种物品和一个背包,
物品i的重量是wi, 价值是vi, 背包容量为W
•对于每个物品,要么装背包,要么不装
•选择装背包的物品集合,使得物品总重量不超过背包容量W, 且价值和尽量大
限制条件: 1<=n<=100 1<=wi,vi<=100 1<=W<=10000
输入:
4 5
2 3
1 2
3 4
2 2
输出:
7
i表示物品编号
j表示剩余背包容量
1.首先给出最朴素的方法,针对每个物品是否放入背包进行搜索
时间复杂度:O(2^n)
#include<iostream> #define M 100 using namespace std; int n, W; int w[M], v[M]; //从第i个物品开始挑选总重小于j的部分 int ret(int i, int j) { int res; if(i == n)//已经没有剩余的物品 res = 0; else if(j < w[i])//当前物品无法放入 res = ret(i+1, j); else//当前物品放入和不放,取二者最大值 res = max(ret(i+1,j), ret(i+1, j-w[i])+v[i]); return res; } int main() { cin>>n>>W; for(int i = 0; i < n; i++) { cin>>w[i]>>v[i]; } cout<<ret(0, W)<<endl; return 0; }
2.由于上面的方式时间复杂度较大,下面给出了利用记忆数组dp进行优化的方法,把第一次的计算结果记录下来,省掉了以后的计算
时间复杂度:O(nW)
#include<iostream> #include<string.h> #define M 100 using namespace std; int n, W; int w[M], v[M]; int dp[M+1][M+1]; //从第i个物品开始挑选总重小于j的部分 int ret(int i, int j) { if(dp[i][j] >= 0) return dp[i][j]; int res; if(i == n)//已经没有剩余的物品 res = 0; else if(j < w[i])//当前物品无法放入 res = ret(i+1, j); else//当前物品放入和不放,取二者最大值 res = max(ret(i+1,j), ret(i+1, j-w[i])+v[i]); return dp[i][j] = res; } int main() { cin>>n>>W; for(int i = 0; i < n; i++) { cin>>w[i]>>v[i]; } memset(dp, -1, sizeof(dp)); cout<<ret(0, W)<<endl; return 0; }
3.穷竭搜索
#include<iostream> #include<string.h> #define M 100 using namespace std; int n, W; int w[M], v[M]; //sum为目前放入物品的价值总和 int ret(int i, int j, int sum) { int res; if(i == n)//已经没有剩余的物品 res = sum; else if(j < w[i])//当前物品无法放入 res = ret(i+1, j, sum); else//当前物品放入和不放,取二者最大值 res = max(ret(i+1,j,sum), ret(i+1, j-w[i], sum+v[i])); return res; } int main() { cin>>n>>W; for(int i = 0; i < n; i++) { cin>>w[i]>>v[i]; } cout<<ret(0, W, 0)<<endl; return 0; }
4.动态规划
dp[0][j] = 0dp[i+1][j] = dp[i][j] (j<w[i])
= max(dp[i][j],dp[i][j-w[i]]+v[i]) 其他
#include<iostream> #include<string.h> #define M 100 using namespace std; int n, W; int w[M], v[M]; int dp[M+1][M+1]; int main() { int i, j; cin>>n>>W; for(i = 0; i < n; i++) { cin>>w[i]>>v[i]; } memset(dp, 0, sizeof(dp)); for(i = 0; i < n; i++) { for(j = 0; j <= W; j++) { if(j<w[i]) dp[i+1][j] = dp[i][j]; else dp[i+1][j] = max(dp[i][j],dp[i][j-w[i]]+v[i]); } } cout<<dp [W]<<endl; return 0; }
二、完全背包
问题描述:
•给定n种物品和一个背包, 物品i的重量是wi, 价值是vi, 背包容量为W
•对于每个物品,要么装背包,要么不装
•选择装背包的物品集合,使得物品总重量不超过背包容量W, 且价值和尽量大
•每种物品可选多件
输入:
3 7
3 4
4
5
2
3
输出:
10
1.一个三层循环的dp,它的时间复杂度是O(nW^2),效率并不高
dp递推式
dp[0][j] = 0
dp[i+1][j] = max(dp[i+1][j], dp[i][j-k*w[i]+k*v[i]) (k*w[i] <= j)
#include<iostream> #include<string.h> #define M 100 using namespace std; int n, W; int w[M], v[M]; int dp[M+1][M+1]; int main() { int i, j, k; cin>>n>>W; for(i = 0; i < n; i++) { cin>>w[i]>>v[i]; } memset(dp, 0, sizeof(dp)); for(i = 0; i < n; i++) { for(j = 0; j <= W; j++) { for(k = 0; k *w[i] <= j; k++) dp[i+1][j] = max(dp[i+1][j],dp[i][j-k*w[i]]+k*v[i]); } } cout<<dp [W]<<endl; return 0; }
2.优化:修改递推式 时间复杂度为O(nW)
dp[i+1][j] = dp[i][j] (j < w[i])
=
max(dp[i][j],dp[i+1][j-w[i]]+v[i]) 其他
#include<iostream> #include<string.h> #define M 100 using namespace std; int n, W; int w[M], v[M]; int dp[M+1][M+1]; int main() { int i, j, k; cin>>n>>W; for(i = 0; i < n; i++) { cin>>w[i]>>v[i]; } memset(dp, 0, sizeof(dp)); for(i = 0; i < n; i++) { for(j = 0; j <= W; j++) { if(j<w[i]) dp[i+1][j] = dp[i][j]; else dp[i+1][j] = max(dp[i][j],dp[i+1][j-w[i]]+v[i]); } } cout<<dp [W]<<endl; return 0; }
相关文章推荐