【Ybt OJ】[动态规划 第1章] 背包问题 [前半章]

57 篇文章 1 订阅
45 篇文章 0 订阅

「 「 动态规划 」 」 1 1 1章 背包问题 ( ( ( 3 3 3 ) ) )
目录:

A.采药问题
B.货币系统
C.宝物筛选

A . A. A. 例题 1 1 1 采药问题

在这里插入图片描述
洛谷 l i n k link link

分析:

这样的屑题真的需要分析吗

CODE:

#include<iostream>
#include<cstdio>
using namespace std;
const int N=2005;
int w[N],c[N],f[N][N]; 
int main(){
	int m,n; 
	scanf("%d%d",&m,&n);	
	for(int i=1;i<=n;i++) 
		scanf("%d%d",&w[i],&c[i]);
	for(register int i=1;i<=n;i++)
		for(register int j=1;j<=m;j++){
			if(j>=w[i]) f[i][j]=max(f[i-1][j-w[i]]+c[i],f[i-1][j]);  //屑2维01背包
			else f[i][j]=f[i-1][j];
		}
	printf("%d",f[n][m]);
	return 0;
}

B . B. B. 例题 2 2 2 货币系统

在这里插入图片描述
洛谷 l i n k link link

分析:

某凯的疑惑
样例: 3 3 3 19 19 19 10 10 10 6 6 6
19 19 19 6 6 6都会被去掉 因为 19 = 10 + 3 + 3 + 3 19=10+3+3+3 19=10+3+3+3 , , , 6 = 3 + 3 6=3+3 6=3+3
剩下的就是 a n s ans ans了 就可以考虑一个类似桶的 d p dp dp

f i f_i fi表示 i i i最多由多少数拼成 那 f i > 1 f_i>1 fi>1就会被去掉 ( ( (可以由 2 2 2个及以上数拼成 就不需要保留 ) ) )
最后一个____转移: f j = m a x ( f j , f j − a i + 1 ) f_j=max(f_j,f_{j-a_i}+1) fj=max(fj,fjai+1)

CODE:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<bitset>
//#pragma GCC optimize(2)
#define reg register
using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
int T,n,a[105],f[25005],ans;
int main()
{
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d",&n);
		for(int i=1;i<=n;i++)
			scanf("%d",&a[i]);
		ans=0;
		memset(f,0,sizeof(f));
		for(int i=1;i<=n;i++)
			for(int j=a[i];j<=25000;j++)
			{
				if(j==a[i]||f[j-a[i]])
					f[j]=max(f[j],f[j-a[i]]+1);
			}
		for(int i=1;i<=n;i++)
			if(f[a[i]]<=1) ans++;
		printf("%d\n",ans);
	}
	
	return 0;
	
} 

C . C. C. 例题 3 3 3 宝物筛选

在这里插入图片描述
洛谷 l i n k link link

分析:

多重背包 但没完全多重背包 m < = 1 0 5 m<=10^5 m<=105 T L E TLE TLE
考虑优化 可以二进制拆分 也可以单调队列优化

w w w表示重量 v v v表示价值 c c c表示数量 普通转移:
f i , j = m a x ( f i − 1 , j − w × k + v × k ) , ∑ k = 1 c f_{i,j}=max(f_{i-1,j-w\times k}+v\times k),\sum_{k=1}^{c} fi,j=max(fi1,jw×k+v×k),k=1c
单调队列优化转移:
f i , j = m a x ( f i − 1 , w × k + q − v × k ) + v × n , ∑ k = 1 c f_{i,j}=max(f_{i-1,w\times k+q}-v\times k)+v\times n,\sum_{k=1}^{c} fi,j=max(fi1,w×k+qv×k)+v×n,k=1c
其中 q = j q=j q=j m o d mod mod w w w , , , n = j / w n=j/w n=j/w , , , n − k < = c n-k<=c nk<=c

然后枚举余数 q q q单调队列优化每个 q q q

CODE:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<bitset>
//#pragma GCC optimize(2)
#define reg register
using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
const int N=4e4+5;
int n,W,ans,head,tail,que[N],num[N],f[N];
int main()
{
	scanf("%d%d",&n,&W);
	for(int i=1;i<=n;i++)
	{
		int v,w,m;
		scanf("%d%d%d",&v,&w,&m);
		if(w==0){
			ans+=v*m;  //没有重量 就直接+总价值
			continue;
		}
		int k=W/w;
		m=min(m,k);
		for(int yu=0;yu<w;yu++)
		{
			head=tail=0;
			k=(W-yu)/w;
			for(int j=0;j<=k;j++)
			{
				while(head<tail&&f[j*w+yu]-j*v>=que[tail-1])
					tail--;
				num[tail]=j;
				que[tail++]=f[j*w+yu]-j*v;
				while(head<tail&&num[head]<j-m)
					head++;
				f[j*w+yu]=max(f[j*w+yu],que[head]+j*v);  //最终的转移方程
			}
		}
	}
	printf("%d",ans+f[W]);
	
	return 0;
	
} 
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值