来源:JZOJ
题目描述
高中要举行一场蛋糕塔比赛。注意,不是 比赛,而是蛋糕塔比赛。学校会提供 种不同类型的蛋糕,第 种蛋糕的高度为 ,营养价值为 ,并且保证所有蛋糕的高度为 的整数倍,每种类型的蛋糕没有数量限制。
蛋糕塔比赛的规则就是要求按照提供的蛋糕,垒成一个高度不超过
的蛋糕塔,并且要求这个蛋糕塔所有蛋糕的营养价值累加和最高。
因为蛋糕不是很结实,参加比赛的小
发现一个现象,如果某块蛋糕的高度超过
,那么这块蛋糕下面的所有蛋糕的高度都将被压缩为自己高度的
,但是营养价值不会丢失。发现这个情况后的小
很兴奋,现在他想知道,如何安排自己的蛋糕塔,能让营养价值最高。
解题思路
- 仍然是一道
(抹不去的心酸),
显然是完全背包的变形,蛋糕能压缩,这个问题有点烦。那么,如何处理呢?O(∩_∩)O - 首先,我们不用超过 的大蛋糕,就按小蛋糕做一遍完全背包,(如果完全背包不会的话,自行查资料)当然了,循环 当然不只是枚举到 了,考虑压缩的情况,应该枚举到 ;
- 然后再一重循环枚举大蛋糕, 就是这个蛋糕放在最上面把下面所有的蛋糕压缩得到的营养价值,为什么 就是大蛋糕下面能达到的高度?因为我们想 是压缩后大蛋糕下面所有蛋糕的最大高度,它们都被压缩成了原来高度的 所以我们 就是蛋糕压缩前能达到的最大高度,这样做就十分方便了;
Code
#include <bits/stdc++.h>
using namespace std;
int v[105],h[105],dp[2010];
int n,t,k,ans=0;
void Dp()
{
memset(dp,0,sizeof(dp));
for (int i=1;i<=n;i++)
for (int j=h[i];j<=t*5/4;j++)
dp[j]=max(dp[j],dp[j-h[i]]+v[i]); //完全背包
}
void work()
{
ans=dp[t];
for (int i=1;i<=n;i++)
if (h[i]>=k) ans=max(ans,dp[(t-h[i])*5/4]+v[i]); //取大蛋糕
}
int main()
{
freopen("cheese..in","r",stdin);
freopen("cheese..out","w",stdout);
scanf("%d %d %d",&n,&t,&k);
for (int i=1;i<=n;i++) scanf("%d %d",&v[i],&h[i]);
Dp();
work();
printf("%d",ans);
return 0;
}