1.完全背包问题
完全背包问题即0-1背包问题的扩展,每个物品都有无穷件,即相同物品可累加放入背包;
问题描述:有一个容积为V的背包,同时有n种物品,有对应种类的体积w和价值v,且每种物品有无穷件;求该背包最多能装下的物品价值总和。
分析问题:
将完全背包问题转换为0-1背包问题,背包对每种物品能装入V/wi件,所以转换为0-1背包问题则物品总数N为
状态描述:dp[i][j]表示第i件物品对于当前占用容量为j的价值状态,其中1<=i<=N,0<=j<=V;
状态分析:第i件物品是否加入背包,
(1)加入,dp[i][j]等于dp[i-1][j-w]+v,第i-1件相对于j-wi的占容最大价值的最大价值加第i件价值;
(2) 没加入,d[i][j]等于dp[i-1][j],即与第i-1件到j占容的最大价值;
状态转换:
转换结果:dp[N][V],第N件物品到占容为V的最大价值状态,即完全背包问题的最优价值总和。
时间复杂度分析:
测试数据:
input: V、 n 和 n种物品的 w and v
10 3
3 3
7 7
9 9ouput:最优价值总和
10
状态矩阵:
i \ j 1 2 3 4 5 6 7 8 9 10 1(3,3) 0 0 3 3 3 3 3 3 3 3 2(3,3) 0 0 3 3 3 3+3 6 6 6 6 3(3,3) 0 0 3 3 3 6 6 6 9 9 4(7,7) 0 0 0 0 0 0 0+7 7 9 3+7(10) 5(9,9) 0 0 0 0 0 0 0 0 0+9 10
Code 转换为0-1背包:
#include <iostream>
#include <stdio.h>
#include <vector>
using namespace std;
int V,n,N;//V为容量,n为种类数,N为0-1背包问题对应的物品个数
vector<int> dpcol(1000,0);
vector<vector<int>> dp(100,dpcol);
struct goods{
int w;//权重或表示为占容
int v;//价值value
};
vector<goods> goodsClass(100,{0,0});//物品种类
vector<goods> goods(1000,{0,0});//转换为0-1背包问题的物品个数
int main(){
int w,v;
while(cin>>V>>n){
for(int i=1;i<=n;i++){
cin>>w>>v;
goodsClass[i]={w,v};
}//输入物品
N=0;
goods.clear();
goods.push_back({0,0});//0位置置空
for(int i=1;i<=n;i++){
int num=V/goodsClass[i].w;
N+=num;
goods.insert(goods.end(), num,goodsClass[i]);
}
for(int j=1;j<=V;j++){
dp[0][j]=0;
}//初始化第0件状态
for(int i=1;i<=N;i++){//物品总数N
for(int j=V;j>=goods[i].w;j--){//体积
dp[i][j]=max(dp[i-1][j-goods[i].w]+goods[i].v,dp[i-1][j]);
}
for(int j=goods[i].w-1;j>=1;j--)
dp[i][j]=dp[i-1][j];
}
cout<<dp[N][V]<<endl;
}
return 0;
}
/**
10 3
3 3
7 7
9 9
0 0 3 3 3 3 3 3 3 3
0 0 3 3 3 6 6 6 6 6
0 0 3 3 3 6 6 6 9 9
0 0 3 3 3 6 7 7 9 10
0 0 3 3 3 6 7 7 9 10
6 5
1 1
5 3
10 3
6 8
7 5
1 1 1 1 1 1
1 2 2 2 2 2
1 2 3 3 3 3
1 2 3 4 4 4
1 2 3 4 5 5
1 2 3 4 5 6
1 2 3 4 5 6
1 2 3 4 5 8
20 4
3 7
2 5
4 6
5 9
0 0 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7
0 0 7 7 7 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14
0 0 7 7 7 14 14 14 21 21 21 21 21 21 21 21 21 21 21 21
0 0 7 7 7 14 14 14 21 21 21 28 28 28 28 28 28 28 28 28
0 0 7 7 7 14 14 14 21 21 21 28 28 28 35 35 35 35 35 35
0 0 7 7 7 14 14 14 21 21 21 28 28 28 35 35 35 42 42 42
0 5 7 7 12 14 14 19 21 21 26 28 28 33 35 35 40 42 42 47
0 5 7 10 12 14 17 19 21 24 26 28 31 33 35 38 40 42 45 47
0 5 7 10 12 15 17 19 22 24 26 29 31 33 36 38 40 43 45 47
0 5 7 10 12 15 17 20 22 24 27 29 31 34 36 38 41 43 45 48
0 5 7 10 12 15 17 20 22 25 27 29 32 34 36 39 41 43 46 48
0 5 7 10 12 15 17 20 22 25 27 30 32 34 37 39 41 44 46 48
0 5 7 10 12 15 17 20 22 25 27 30 32 35 37 39 42 44 46 49
0 5 7 10 12 15 17 20 22 25 27 30 32 35 37 40 42 44 47 49
0 5 7 10 12 15 17 20 22 25 27 30 32 35 37 40 42 45 47 49
0 5 7 10 12 15 17 20 22 25 27 30 32 35 37 40 42 45 47 50
0 5 7 10 12 15 17 20 22 25 27 30 32 35 37 40 42 45 47 50
0 5 7 10 12 15 17 20 22 25 27 30 32 35 37 40 42 45 47 50
0 5 7 10 12 15 17 20 22 25 27 30 32 35 37 40 42 45 47 50
0 5 7 10 12 15 17 20 22 25 27 30 32 35 37 40 42 45 47 50
0 5 7 10 12 15 17 20 22 25 27 30 32 35 37 40 42 45 47 50
0 5 7 10 12 15 17 20 22 25 27 30 32 35 37 40 42 45 47 50
0 5 7 10 12 15 17 20 22 25 27 30 32 35 37 40 42 45 47 50
0 5 7 10 12 15 17 20 22 25 27 30 32 35 37 40 42 45 47 50
0 5 7 10 12 15 17 20 22 25 27 30 32 35 37 40 42 45 47 50
*/
//Code 0-1背包一维dp
#include <iostream>
#include <stdio.h>
#include <vector>
using namespace std;
int V,n,N;//V为容量,n为种类数,N为0-1背包问题对应的物品个数
vector<int> dp(100,0);
struct goods{
int w;//权重或表示为占容
int v;//价值value
};
vector<goods> goodsClass(101,{0,0});//物品种类
vector<goods> goods(1001,{0,0});//转换为0-1背包问题的物品个数
int main(){
int w,v;
while(cin>>V>>n){
for(int i=1;i<=n;i++){
cin>>w>>v;
goodsClass[i]={w,v};
}//输入物品
N=0;
goods.clear();
goods.push_back({0,0});//0位置置空
for(int i=1;i<=n;i++){
int num=V/goodsClass[i].w;
N+=num;
goods.insert(goods.end(), num,goodsClass[i]);
}
for(int j=0;j<=V;j++){
dp[j]=0;
}
//0-1,一维
for(int i=1;i<=N;i++){//物品总数N
for(int j=V;j>=goods[i].w;j--){//体积
dp[j]=max(dp[j-goods[i].w]+goods[i].v,dp[j]);
}
for(int j=1;j<=V;j++){//体积
cout<<dp[j]<<" ";
}
cout<<endl;
}
cout<<dp[V]<<endl;
}
return 0;
}
Code 完全背包二维dp:
//二维dp
#include <iostream>
#include <stdio.h>
#include <vector>
using namespace std;
int V,N;//V为容量,N为种类数
vector<int> dpcol(101,0);
vector<vector<int>> dp(101,dpcol);
struct goods{
int w;//权重或表示为占容
int v;//价值value
};
vector<goods> goodsClass(101,{0,0});//物品种类
int main(){
int w,v;
while(cin>>V>>N){
for(int i=1;i<=N;i++){
cin>>w>>v;
goodsClass[i]={w,v};
}//输入物品
for(int j=0;j<=V;j++){
dp[0][j]=0;
}//初始化第0件状态
for(int i=1;i<=N;i++){//物品总数N
for(int j=1;j<=V;j++){//顺序
if(j<goodsClass[i].w){//一个装不下
dp[i][j]=dp[i-1][j];//copy上一轮价值到j最大价值
}else{//能装
if(dp[i-1][j]<dp[i-1][j-goodsClass[i].w]+goodsClass[i].v){//不装价值更小
dp[i][j]=dp[i][j-goodsClass[i].w]+goodsClass[i].v;
}else{
dp[i][j]=dp[i-1][j];
}
}
}
}
for(int i=1;i<=N;i++){
for(int j=1;j<=V;j++)
cout<<dp[i][j]<<" ";
cout<<endl;
}
}
return 0;
}
/**
10 3
3 3
7 7
9 9
0 0 3 3 3 6 6 6 9 9
0 0 3 3 3 6 7 7 9 10
0 0 3 3 3 6 7 7 9 10
6 5
1 1
5 3
10 3
6 8
7 5
1 2 3 4 5 6
1 2 3 4 5 6
1 2 3 4 5 6
1 2 3 4 5 8
1 2 3 4 5 8
20 4
3 7
2 5
4 6
5 9
0 0 7 7 7 14 14 14 21 21 21 28 28 28 35 35 35 42 42 42
0 5 7 10 12 15 17 20 22 25 27 30 32 35 37 40 42 45 47 50
0 5 7 10 12 15 17 20 22 25 27 30 32 35 37 40 42 45 47 50
0 5 7 10 12 15 17 20 22 25 27 30 32 35 37 40 42 45 47 50
*/
二维到一维优化状态转换:
vector<int> dp(100,0);
for(int i=1;i<=N;i++){//物品种类数N
for(int j=goods[i].w;j<=V;j++){//体积
dp[j]=max(dp[j-goods[i].w]+goods[i].v,dp[j]);
//dp[j]前i-1件物品相对于体积j的价值,未添加第i件物品
//dp[j-goods[i].w]+goods[i].v,前i-1件物品相对于添加第i件物品价值后相对于体积j的价值
}
}
cout<<dp[V]<<endl;
//一维dp
#include <iostream>
#include <stdio.h>
#include <vector>
using namespace std;
int V,N;//V为容量,N为种类数
vector<int> dp(1000,0);
struct goods{
int w;//权重或表示为占容
int v;//价值value
};
vector<goods> goodsClass(100,{0,0});//物品种类
int main(){
int w,v;
while(cin>>V>>N){
for(int i=1;i<=N;i++){
cin>>w>>v;
goodsClass[i]={w,v};
}//输入物品
for(int j=0;j<=V;j++){
dp[j]=0;
}//初始化第0件状态
for(int i=1;i<=N;i++){//物品总数N
for(int j=goodsClass[i].w;j<=V;j++){//体积
dp[j]=max(dp[j-goodsClass[i].w]+goodsClass[i].v,dp[j]);
}
for(int j=1;j<=V;j++)
cout<<dp[j]<<" ";
cout<<endl;
}
cout<<dp[V]<<endl;
}
return 0;
}