BZOJ 3174: [Tjoi2013]拯救小矮人

Description

一群小矮人掉进了一个很深的陷阱里,由于太矮爬不上来,于是他们决定搭一个人梯。即:一个小矮人站在另一小矮人的 肩膀上,知道最顶端的小矮人伸直胳膊可以碰到陷阱口。对于每一个小矮人,我们知道他从脚到肩膀的高度Ai,并且他的胳膊长度为Bi。陷阱深度为H。如果我 们利用矮人1,矮人2,矮人3,。。。矮人k搭一个梯子,满足A1+A2+A3+....+Ak+Bk>=H,那么矮人k就可以离开陷阱逃跑了,一 旦一个矮人逃跑了,他就不能再搭人梯了。
我们希望尽可能多的小矮人逃跑, 问最多可以使多少个小矮人逃跑。

Input

第一行一个整数N, 表示矮人的个数,接下来N行每一行两个整数Ai和Bi,最后一行是H。(Ai,Bi,H<=10^5)

Output

一个整数表示对多可以逃跑多少小矮人

Sample Input

样例1

2
20 10
5 5
30

样例2
2
20 10
5 5
35

Sample Output

样例1
2

样例2
1

HINT

数据范围

30%的数据 N<=200

100%的数据 N<=2000

题解:

  这个题目,首先我们肯定会想出很多贪心吧!然而每一个贪心都……其中有一个贪心是这样的,按照Ai+Bi排序,然后先看小的,如果可以走就走,但这个贪心是有问题的,就是假如有一个人,他本来可以走,但是如果他不走可以多挽救>1个人,那么显然他不走更优秀。所以这个东西是需要决策的,判断这个人十分让他走,但这个贪心有一定的可取只出。就是你走的顺序,一定是按照你排序后的顺序来走到,即:如果将排序后的人重新编号,那么走的顺序一定是类似于1,3,5这样的递增序列,而不是3,1,5这样的。

  所以这个问题就转化成了,一个01背包的变种问题,我们考虑设dp[i]表示走了i个人的剩余人的最大高度,那么决策就是第i个人走或者不走。因为可能剩下的高度为0,所以初始化要为-1,这个题目猜到那个结论,有知道要dp就不难了。

代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
#define MAXN 30000
using namespace std;
int dp[MAXN];
struct people{
    int hi,shou;
}a[MAXN];
int n,dep;

bool cmp(people x,people y){
    return x.hi+x.shou<y.hi+y.shou;
}

int main()
{
    scanf("%d",&n);int sum=0;
    for(int i=1;i<=n;i++){
        scanf("%d%d",&a[i].hi,&a[i].shou);
        sum+=a[i].hi;
    }
    sort(a+1,a+n+1,cmp);
    memset(dp,-1,sizeof(dp));
    dp[0]=sum;int h=0;
    scanf("%d",&dep);
    for(int i=1;i<=n;i++){
        for(int j=h;j>=0;j--){
            if(dp[j]+a[i].shou>=dep) dp[j+1]=max(dp[j+1],dp[j]-a[i].hi);
            if(dp[j+1]>=0) h=max(h,j+1);
        }
    }
    printf("%d",h);
    return 0;
}
原文地址:https://www.cnblogs.com/renjianshige/p/7590733.html