完全背包问题

1.完全背包问题

完全背包问题即0-1背包问题的扩展,每个物品都有无穷件,即相同物品可累加放入背包;

问题描述:有一个容积为V的背包,同时有n种物品,有对应种类的体积w和价值v,且每种物品有无穷件;求该背包最多能装下的物品价值总和。

分析问题:

将完全背包问题转换为0-1背包问题,背包对每种物品能装入V/wi件,所以转换为0-1背包问题则物品总数N为\sum _{i=1}^n V/w_i

状态描述: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[0][j]&=0; \\dp[i][j]&=max\lbrace dp[i-1][j-w]+v,dp[i-1][j]\rbrace (j-w> 0)

转换结果:dp[N][V],第N件物品到占容为V的最大价值状态,即完全背包问题的最优价值总和。

时间复杂度分析:

O(V\ast \sum _{i=1}^n V/w_i)

测试数据:

input: V、 n 和 n种物品的 w and v

10 3
3 3
7 7
9 9

ouput:最优价值总和

10

状态矩阵:

i \ j12345678910
1(3,3)0033333333
2(3,3)003333+36666
3(3,3)0033366699
4(7,7)0000000+7793+7(10)
5(9,9)000000000+910

 

 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;
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值