奶酪塔

题意:在n块奶酪中选取若干块总高度不超过t的奶酪,使其价值最大。其中,高度在k以上的奶酪可以挤压它下面的奶酪,使他们的高度只有原来的4/5.
分析:首先,从题目中就可以看出这是一道完全背包的题目,但是由于高度大于k的奶酪会使它下面的奶酪高度变小,所以需要把状态拆分。所以我们可以在完全背包的基础上在加一层,用f[i][0]表示高度为i且存在大奶酪的最优解,用f[i][1]表示高度为i且不存在大奶酪的最优解。
对于没有大奶酪的情况我们可以直接用完全背包的状态转移方程搞定,但是在有大奶酪的情况下我们还需要考虑到大奶酪的位置,用贪心思想不难得出大奶酪一定要放在最上面才是最优解(可以挤压更多的奶酪),若是有两个以上的大奶酪,则要把高度最小的大奶酪放到最上面(都放在上面大奶酪不会被挤压到,高度不变,所以要把这个位置留给高度最小的大$奶酪)。
所以我们要把所有的大奶酪从小到大排列,先选大奶酪。一开始,所有的f[j][1]都要定义成无解,当第i个是大奶酪时,它的值就等于 f[(ja[i].w)4/5][0]+a[i].v (选取第i个奶酪,这样就有大奶酪了)。所以会有:
               f[j][0]=max(f[j][0],f[j-a[i].w][0]+a[i].v) ; 
         f[j][1]=max(f[j][1],f[j-a[i].w*4/5][1]+a[i].v) ;(当f[j-a[i].w*4/5][1]存在解时)
         f[j][1]=max(f[j][1],f[(j-a[i].w)*4/5][0]+a[i].v) ;(当第i个是大奶酪时)
最后的答案就是 max(f[m][0],f[m][1])
参考代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std ;
const int maxn=110,maxm=1010 ;
struct t{int v,w;}a[maxn] ;
bool cmp1(t a,t b)
{
    return a.w>b.w ;
}
bool cmp2(t a,t b)
{
    return a.w<b.w ;
}
int n,m,k,temp,f[maxm][2] ;
int main()
{
    freopen("chess.in","r",stdin) ;
    freopen("chess.out","w",stdout) ;

    scanf("%d%d%d",&n,&m,&k) ;
    for (int i=1;i<=n;i++)
        scanf("%d%d",&a[i].v,&a[i].w) ;
    for (int i=1;i<=m;i++) f[i][1]=-1 ;
    sort(a+1,a+1+n,cmp1) ;
    for (;a[temp+1].w>=k;temp++) ;
    sort(a+1,a+1+temp,cmp2) ;

    for (int i=1;i<=n;i++)
        for (int j=a[i].w;j<=m;j++)
        {
            f[j][0]=max(f[j][0],f[j-a[i].w][0]+a[i].v) ;
            if (f[j-a[i].w*4/5][1]!=-1) f[j][1]=max(f[j][1],f[j-a[i].w*4/5][1]+a[i].v) ;
            if (a[i].w>=k) f[j][1]=max(f[j][1],f[(j-a[i].w)*4/5][0]+a[i].v) ;
        }

    printf("%d",max(f[m][0],f[m][1])) ;

    return 0 ;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值