多重背包二进制优化详解
查看原帖
多重背包二进制优化详解
1081095
Believe_in_dreams楼主2024/6/7 21:29
//多重背包的二进制优化的空间优化
/*
观念:
把多个相同的物品合并成为一个大物品
如何合并:
使用二进制把每一类物品的总个数进行拆分,这样每一种组合(选择这种物品的个数)都能通过选择这些大物品凑成,而且物品数量变成了n*log级别
例1:6个1
可以凑成0,1,2,3,4,5,6
变成1,2,3后也能凑成0,1,2,3,4,5,6
例2:10个2
可以凑成0,2,4,6,...,20
变成1,2,4,3后也能凑成0,2,4,6,...,20
*/
#include<bits/stdc++.h>
using namespace std;
const int MAXG=2e6+1,MAXM=2e5+1;//二进制优化后最大物品个数和背包容量的最大值
int n,m,v[MAXG],w[MAXG],dp[MAXM],id,win,vin,s;
/*
有n种物品,背包容量为m,每一种物品有v价值,w重量,s个数
dp为滚动数组
id为物品个数
*/
int main(){
	scanf("%d%d",&n,&m);//n个物品,背包容量为m
	for(int i=1;i<=n;i++){
		scanf("%d%d%d",&vin,&win,&s);
		//对s[i]进行二进制拆分
		int f=1;
		while(f<=s){//拆分到拆不动为止
			w[++id]=win*f;
			v[id]=vin*f;
			s-=f;
			f*=2;//按照2的幂次进行拆分
		}
		if(s){//拆分存在剩余
			w[++id]=win*s;
			v[id]=vin*s;
		}
	}
	for(int i=1;i<=id;i++){//有id件物品
		for(int j=m;j>=w[i];j--){//01背包的做法
			dp[j]=max(dp[j],dp[j-w[i]]+v[i]);//状态转移方程
		}
	}
	cout<<dp[m];
	return 0;
}
2024/6/7 21:29
加载中...