5.29身败名裂

这篇博客探讨了编程竞赛中动态规划的巧妙运用,通过三个实例——完全背包、多重背包和二维背包问题,详细解释了如何将动态规划与物品体积、价值和限制条件相结合,解决复杂的问题。代码示例展示了如何高效地计算最小成本和最大收益,强调了初始化、方案累加以及避免背包溢出等关键点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

busses

本题第一眼可能会让人迷惑,拨开题面看本质,这里里程其实可以看作十种物品同时里程也是所占体积,耗油数就是价值,随意换乘意味着物品可以取随意多件,那么这就是一个完全背包,总体积为想要行驶的里程数
代码:

#include<bits/stdc++.h>
#define N 1000005
#define ll long long
using namespace std;
inline int read(){
	int x=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=x*10+c-'0';c=getchar();}
	return x*f;
}
int a[20],dp[500],d[11]={0,1,2,3,4,5,6,7,8,9,10};
int main(){
	for(int i=1;i<=499;i++)dp[i]=1e9;
	for(int i=1;i<=10;i++)a[i]=read();
	int n=read();
	for(int i=1;i<=10;i++)
		for(int j=d[i];j<=n;j++)
			dp[j]=min(dp[j],dp[j-d[i]]+a[i]);
	printf("%d",dp[n]);
	return 0;
}

注意:这里求最小值,要注意dp数组的初始化

prime

本题迷惑性极强,很容易让人去打素数表用数学方法求解,但如果我们将素数作为多个物品,素数的大小作为体积,本题就又变成了一个完全背包
代码:

#include<bits/stdc++.h>
#define N 1000005
#define ll long long
using namespace std;
inline int read() {
	int x=0,f=1;
	char c=getchar();
	while(!isdigit(c)) {
		if(c=='-')f=-1;
		c=getchar();
	}
	while(isdigit(c)) {
		x=x*10+c-'0';
		c=getchar();
	}
	return x*f;
}
int prime[1005],pcnt,cnt[1005];
ll  dp[1005];
int used[1005];
int isprime[1005];
int main() {
	for(int i=2; i<=200; i++) {
		int flag=0;
		for(int j=2; j<i; j++)
			if(!(i%j)) {
				flag=1;
				break;
			}
		if(!flag) {
			prime[++pcnt]=i;
			isprime[i]=1;
		}
	}
	dp[0]=1;
	for(int i=1; i<=pcnt; i++)
		for(int j=prime[i]; j<=200; j++)
			dp[j]+=dp[j-prime[i]];
	int n;
	while(scanf("%d",&n)!=EOF)printf("%lld\n",dp[n]);
	return 0;
}

注意:
1、方案数需要求和而不是取最大值
2、多测可以离线计算,一定要注意到多测!

hallows

多重背包板子,要注意背包溢出问题
代码:

#include<bits/stdc++.h>
#define N 10005
#define ll long long
using namespace std;
inline ll read(){
	int x=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=x*10+c-'0';c=getchar();}
	return x*f;
}
ll m[N],w[N],s[N],dp[N];
int main(){
	ll n=read(),v=read();
	for(int i=1;i<=n;i++){m[i]=read();w[i]=read();s[i]=read();}
	for(int i=1;i<=n;i++)
		for(int j=v;j>=w[i];j--)
			for(int k=1;k<=m[i]&&j>=k*w[i];k++)
				dp[j]=max(dp[j],dp[j-k*w[i]]+k*s[i]);
	printf("%lld",dp[v]);
	return 0;
}

pgrune

多重+二维背包,可以使用哈希合并维度(不建议使用)
代码:

#include<bits/stdc++.h>
#define N 10005
#define ll long long
using namespace std;
inline ll read(){
	int x=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=x*10+c-'0';c=getchar();}
	return x*f;
}
ll p[N],r[N],dp[N][N],v[N],m[N];
int main(){
	ll n=read(),P=read(),R=read();
	for(int i=1;i<=n;i++){p[i]=read(),r[i]=read(),m[i]=read(),v[i]=read();if(!m[i])m[i]=1e9;}
	for(int i=1;i<=n;i++)
		for(int x=P;x>=p[i];x--)
			for(int y=R;y>=r[i];y--)
				for(int k=1;k<=m[i]&&x>=k*p[i]&&y>=k*r[i];k++)
					dp[x][y]=max(dp[x][y],dp[x-k*p[i]][y-k*r[i]]+k*v[i]);
	printf("%lld",dp[P][R]);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值