多重背包问题

1.多重背包问题

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

分析问题:

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

状态描述: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[j]=max \lbrace dp[j] ,dp[j-w]+v \rbrace

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

时间复杂度分析:O(V\ast\sum_{i-1}^n min\lbrace k_i,V/w_i\rbrace)

测试数据集:

1
8 2
4 100 2
2 100 4

状态矩阵:
0 0 0 100 100 100 100 100 
0 0 0 100 100 100 100 200 
0 100 100 100 100 200 200 200 
0 100 100 200 200 200 200 300 
0 100 100 200 200 300 300 300 
0 100 100 200 200 300 300 400 

Code(转换为0-1) :

#include <iostream>
#include <stdio.h>
#include <vector>
using namespace std;
int main(){
	int C;
	int V,N;
	struct goods{
		int w;
		int v;
	};
	vector<int> dp(101,0);
	vector<goods> goods(1,{0,0});//物品总数
	int w,v,k;
	cin>>C;
	while(C--){
		goods.erase(goods.begin()+1, goods.end());
		cin>>V>>N;
		int n=0;
		for(int i=1;i<=N;i++){
			cin>>w>>v>>k;
			n+=min(k,V/w);
			goods.insert(goods.end(), min(k,V/w), {w,v});
		}
		for(int j=0;j<=V;j++){
			dp[j]=0;
		}
		for(int i=1;i<=n;i++){//物品最大总数N
			for(int j=V;j>=goods[i].w;j--){//0-1,逆序
				dp[j]=max(dp[j],dp[j-goods[i].w]+goods[i].v);
			}
			for(int j=1;j<=V;j++)
				cout<<dp[j]<<" ";
			cout<<endl;
		}
		cout<<dp[V]<<endl;
	}
	return 0;
}

简化0-1代码:

struct goodsClass{
    int w;
    int v;
    int k;
}
for(int i=i;i<N;i++){//N为物品种类数
    for(int j=V;j>goodsClass[i].w;j--){//自右向左,自左向右都可,逆序便于理解0-1背包
        for(int k=1;k<goodsClass[i].k&&j>=k*goodsClass[i].w;k++){
            dp[j]=max(dp[j],dp[j-k*goodsClass[i].w]+k*goodsClass[i].v);
        }
    }
}//求多重背包

以上简化时间复杂度为O(V*\sum_{i=1}^Nk_i),若想优化其复杂度可使用二进制拆分法转换为以组为单位的0-1背包问题,其时间复杂度为O(V*\sum_{i=1}^Nlog_2(k_i)),或是借助单调队列实现,其复杂度为O(V*N).

*扩展

基于上述0-1简化代码,可实现对完全背包问题求解:

for(int i=1;i<=N;i++){
    for(int j=V;j>=goodsClass[i].w;j--){
        for(int k=1;j>=k*goodsClass[i].w;k++){//j>=k*goodsClass[i].w确保dp不越界,同时保证1<=k<=V/goodsClass[i].w
            dp[j]=max(dp[j],dp[j-k*goodsClass[i].w]+k*goodsClass[i].v);
        }
    }
}

最后建议:求背包问题都转换为0-1背包问题,若需要优化则再考虑优化。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值