[USACO10JAN]奶酪塔Cheese Towers

本文介绍了一个关于奶酪塔建造的问题,通过动态规划(DP)解决如何在有限高度下,使用不同类型的奶酪(高度和价值各异)构建价值最大的塔。问题考虑了特殊条件,即大奶酪会影响其下方奶酪的高度。文章详细解析了从上至下的DP策略,包括状态定义、转移方程和代码实现。

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

题目描述

FJ要建一个奶酪塔,高度最大为T。他有N种奶酪(每种奶酪无限个)。第i种奶酪的高度为Hi(一定是5的倍数),价值为Vi。一块高度Hi>=K的奶酪被称为大奶酪,一个奶酪如果在它上方有大奶酪(如果有多块就只算一次),它的高度Hi就会变成原来的4/5.。FJ想让他的奶酪塔价值和最大。请你求出这个最大值。

输入格式:

第一行三个数N,T,K,意义如上所述。 接下来n行,每行两个数V_i,h_i(注意顺序)

输出格式:

奶酪塔的最大价值

(1 <= T <= 1,000).

N (1 <= N <= 100) 

(1 <= V_i <= 1,000,000)

H_i (5 <= H_i <= T)

这一题不难看出是背包问题,因为dp在这一道题无后效性!

而且N和T的值很小,背包的时间是O(NT),完全承受的了的

可是如果直接从底往上搜,就会很难判断出上面是否有大奶酪,那我们怎么办呢?

既然直接模拟不行,那我们换个方向总行吧!

所以我们直接从上往下找

//dp[i][0]表示第i高度,没有大奶酪的最大值
//dp[i][0]表示第i高度,有大奶酪的最大值

就可以推出动态方程了

首先是头文件和定义的数组:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<queue>
#include<stack>
#include<map>
#include<cmath>
#include<string>
#include<set>
#include<ctime>
using namespace std;
inline int read(){
	int x=0,f=0;char s=getchar();
	while(!isdigit(s))f|=s=='-',s=getchar();
	while( isdigit(s))x=(x<<1)+(x<<3)+s-48,s=getchar();
	return !f?x:-x;
}
inline void print(int x){
     if(x<0)putchar('-'),x=-x;
     if(x>9)print(x/10);
     putchar(x%10+'0');
}
const int N=2e2+20;
const int T=2e3+20;
int n,t,k;
struct node{
	int v,h;
}a[N];
int dp[T][2];
//dp[i][0]表示第i高度,没有大奶酪的最大值
//dp[i][0]表示第i高度,有大奶酪的最大值

然后是输入和初始化

dp一开始全部为0,表示不可用,边界dp[0][0]=0

n=read();t=read();k=read();
	for(int i=1;i<=n;i++)a[i].v=read(),a[i].h=read();
	memset(dp,-1,sizeof(dp));dp[0][0]=0;

然后是核心的dp

我们可以分3种不同的情况进行讨论

1:

当前已经有大奶酪了,就推出dp[ki+a[i].h/5*4][1]

2:

当前无大奶酪,推出dp[ki+a[i].h][0]

3:

当前无大奶酪并且这个就是大奶酪,利用dp[ki][0]推出dp[ki+a[i].h][1]

代码:

for(int ki=0;ki<=t;ki++){
	for(int i=1;i<=n;i++){
		if(ki+a[i].h/5*4<=t&&dp[ki][1]!=-1)
			dp[ki+a[i].h/5*4][1]=max(dp[ki+a[i].h/5*4][1],dp[ki][1]+a[i].v);
		if(ki+a[i].h    <=t&&dp[ki][0]!=-1)
			dp[ki+a[i].h    ][0]=max(dp[ki+a[i].h    ][0],dp[ki][0]+a[i].v);
		if(a[i].h>=k	   &&dp[ki][0]!=-1)
			dp[ki+a[i].h    ][1]=max(dp[ki+a[i].h    ][1],dp[ki][0]+a[i].v);
	}
}

以及最后的输出

int maxx=-1;
for(int i=0;i<=t;i++)maxx=max(maxx,max(dp[i][0],dp[i][1]));
print(maxx);

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值