算法笔记|动态规划2024/05/01(背包问题)

01背包问题

二维

#include<iostream>
#include<algorithm>
#include<cstdio>

using namespace std;

const int N=1010;

int n,m;//物品数量n和背包容积m都小于1000
int v[N],w[N];//每件物品的体积和价值
int f[N][N]; //f(i,j)表示从前i个物品中选出总体积不超过j的价值的最大值

int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>v[i]>>w[i];//完成输入
	
	for(int i=1;i<=n;i++){
		for(int j=0;j<=m;j++){
			f[i][j]=f[i-1][j];//左边一定存在
			if(j>=v[i]) f[i][j]=max(f[i][j],f[i-1][j-v[i]]+w[i]);//右边不一定存在,仅当总体积j大于v[i]时才存在这种情况
		}
	}
	
	cout<<f[n][m]<<endl;
} 

一维

#include<iostream>
#include<algorithm>
#include<cstdio>

using namespace std;

const int N=1010;

int n,m;//物品数量n和背包容积m都小于1000
int v[N],w[N];//每件物品的体积和价值
int f[N];

int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>v[i]>>w[i];//完成输入
	
	for(int i=1;i<=n;i++){
		for(int j=m;j>=v[i];j--){//从大到小枚举
			f[j]=max(f[j],f[j-v[i]]+w[i]);
    	}
	}
	
	cout<<f[m]<<endl;
} 

完全背包问题

暴力(会超时)

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>

using namespace std;

const int N = 1010;
int n,m;
int v[N],w[N];
int f[N][N];

int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++) {
		cin>>v[i]>>w[i];
	}
	for(int i=1;i<=n;i++){
		for(int j=0;j<=m;j++){
			for(int k=0;k*v[i]<=j;k++) //k是第i个物品的个数
				f[i][j]=max(f[i][j],f[i-1][j-k*v[i]]+w[i]*k);
		}
	}
	
	cout<<f[n][m]<<endl;
	return 0;
} 

优化(二维)

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>

using namespace std;

const int N = 1010;
int n,m;
int v[N],w[N];
int f[N][N];

int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++) {
		cin>>v[i]>>w[i];
	}
	for(int i=1;i<=n;i++){
		for(int j=0;j<=m;j++){
			f[i][j] = f[i-1][j];
			if(v[i]<=j) f[i][j] = max(f[i][j],f[i][j-v[i]]+w[i]);
		}
	}
	
	cout<<f[n][m]<<endl;
	return 0;
} 

优化(一维)

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>

using namespace std;

const int N = 1010;
int n,m;
int v[N],w[N];
int f[N];

int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++) {
		cin>>v[i]>>w[i];
	}
	for(int i=1;i<=n;i++){
		for(int j=v[i];j<=m;j++){
		    f[j] = max(f[j],f[j-v[i]]+w[i]);//都是第i层的,不需要改动了
		}
	}
	
	cout<<f[m]<<endl;
	return 0;
} 

!!!对于体积j:01背包从大到小循环  完全背包从小到大循环!!!

多重背包问题

暴力写法:三重循环

#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstdio>

using namespace std;

const int N=105;
int v[N],w[N],s[N];
int f[N][N];


int main(){
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++) 
		cin>>v[i]>>w[i]>>s[i];
	
	for(int i=1;i<=n;i++){
		for(int j=0;j<=m;j++){
			for(int k=0;k<=s[i]&&k*v[i]<=j;k++){
				f[i][j]= max(f[i][j],f[i-1][j-v[i]*k]+w[i]*k);
			}
		}
	}
	cout<<f[n][m]<<endl;
	return 0;
}

二进制优化

将多重背包问题转为01背包问题

#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstdio>

using namespace std;
 //物品个数最多是1000*log2000 
const int N = 1000 * 11 + 5; // 11 为log(2000)向上取整
const int M=2005;
int n,m;
int v[N],w[N];
int f[N];// f[j] 表示体积为j的物品的价值总和最大是多少。


int main(){
	cin>>n>>m;
	int cnt=0; //为01背包问题中商品的重数 
	for(int i=1;i<=n;i++){
		int a,b,s;
		cin>>a>>b>>s;
		int k=1;
		while(k<=s) {//每次把k个第i个物品打包在一起 
			cnt++;
			v[cnt] = a*k;
			w[cnt] = b*k;
			s-=k;
			k*=2;
		}
		if(s>0){
			cnt++;
			v[cnt]=a*s;
			w[cnt]=b*s;
		}
	}
	n=cnt;
	for(int i=1;i<=n;i++){
		for(int j=m;j>=v[i];j--){
			f[j]=max(f[j],f[j-v[i]]+w[i]);
		}
	}
	cout<<f[m]<<endl;
	return 0;
}

分组背包问题

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<algorithm>

using namespace std;

const int N=105;
int n,m;
int v[N][N],w[N][N],s[N]; 
int f[N];



int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){ 
		cin>>s[i];
		for(int j=0;j<s[i];j++)
			cin>>v[i][j]>>w[i][j];
	}
	for(int i=1;i<=n;i++){ //枚举每一组 
		for(int j=m;j>=0;j--){ //从大到小枚举所有体积 
			for(int k=0;k<s[i];k++){ //枚举所有选择 
				if(v[i][k]<=j){
					f[j]=max(f[j],f[j-v[i][k]]+w[i][k]);
				}
			}
		}
	}
	cout<<f[m]<<endl;
	return 0;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值