BZOJ3174 TJOI2013 拯救小矮人 贪心+一般DP

题意:有N个小矮人,他们从脚到肩膀的高度Ai,胳膊长度为Bi。陷阱深度为H。如果我们利用矮人1,矮人2,矮人3……矮人k搭一个梯子,满足A1+A2+A3+….+Ak+Bk>=H,那么矮人k就可以离开陷阱逃跑了,一旦一个矮人逃跑了,他就不能再搭人梯了,问最多可以使多少个小矮人逃跑。

题解:

由于不管怎么排,总的高度是不变的,因此关键在于如何找出出洞的次序。

考虑只有a和b两个小矮人,那么如果a先出那么剩余高度就是b.a+b.b,如果b先出那剩余高度就是a.a+a.b,因此关键在于b.a+b.b与a.a+a.b的比较。

当然如果a.a+a.b>b.a+b.b,那肯定让b先出。有没有特殊情况?有。

若a.a+a.b>b.a+b.b,但a.a+b.a+b.b<a.a+b.a+a.b,则假定a.a>a.b+b.b,则a.a+b.a+b.b<a.b+b.a<b.b+a.b+a.a。因此无论怎样,如果走掉a之后剩余的高度比b先走掉剩余的高度大,则一定让a先走掉。

因此将每个小矮人按照a+b排序之后按顺序DP即可。

定义f[i]为走掉i个小矮人之后剩余的最大高度,状态转移方程f[j+1]=max(f[j+1],f[j]-man[i].a),转移的条件是f[j]+man[i].b>=H(即这个小矮人能走掉)。

当f[ans+1]>=0时,ans++。

初始化f[1->n]=-1,f[0]=sum(man[i].a)。

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;

const int MAXN=2000+2;
struct MAN{
    int a,b;
}man[MAXN];
int H,N,f[MAXN],ans;

bool cmp(MAN x,MAN y){return x.a+x.b<y.a+y.b;}

int main(){
    memset(f,-1,sizeof(f));
    f[0]=0;

    cin >> N;
    for(int i=1;i<=N;i++){
        cin >> man[i].a >> man[i].b;
        f[0]+=man[i].a;
    }
    cin >> H;

    sort(man+1,man+N+1,cmp);

    for(int i=1;i<=N;i++)
        for(int j=ans;j>=0;j--){
            if(f[j]+man[i].b>=H) f[j+1]=max(f[j+1],f[j]-man[i].a);
            if(f[ans+1]>=0) ans++;
        }

    cout << ans << endl;

    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/WDZRMPCBIT/p/6477151.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值