http://acm.hdu.edu.cn/showproblem.php?pid=4314

典型的动态规划   首先要确认一点 那就是假设有一定数量的小矮人逃了出去 那么

先逃出去的小矮人 身高+臂长  一定比后逃出的小矮人 身高+臂长  要短  这样才能最优(这个还是看了解析才知道的)

当最顶端的小矮人可以逃出去的话 他可以选择逃或者不逃 如果逃不出去就一定不逃 

要注意的是如果他不逃 就会对后面的小矮人逃走造成一些好的影响 由于他的身高影响(把他放在最下面)会使后面的小矮人更容易接近洞口

处理就在这里 要想办法把这种好的影响记录下来。

假设最 身高+臂长 最大的小矮人 i 值最大

ans[i][j]  表示到第 i 个小矮人逃出去了 j 个人时  可以对后面的小矮人造成的最大好处

如果为 最负(很小的负数) 值则表示无这种情况

找第n个小矮人时 满足要求的最多人逃出

代码及其注释:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>

using namespace std;

const int N=2005;
const int MIN=-1000000000;
struct node
{
    int a,b;
}mem[N];
int L[N];
int ans[N][N];
int H;
bool cmp(node x,node y)
{
    return x.a+x.b<y.a+y.b;
}
int dp(int x,int num)
{
    if(ans[x][num]!=-1)//你懂得
    return ans[x][num];
    if(x==0)//第0 个人
    {
        if(num==0)
        ans[x][num]=0;//如果让逃出0个人 则可以 可以造成0个好的影响
        else
        ans[x][num]=MIN;//否则不存在这种情况 最小负数
        return ans[x][num];
    }
    if(num==0)
    {
        ans[x][num]=mem[x].a+dp(x-1,num);//如果需要逃出0个人 则可以直接把x小矮人的身高加在好的影响点上
        return ans[x][num];
    }
    ans[x][num]=MIN;//先赋值最小负数
    if(dp(x-1,num-1)+mem[x].b+L[x]>=H)//如果存在他可以逃出的情况
    {
        ans[x][num]=dp(x-1,num-1);//记录值
    }
    ans[x][num]=max(ans[x][num],dp(x-1,num)+mem[x].a);//查看x小矮人不逃出去时 是否最优
    return ans[x][num];
}
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=1;i<=n;++i)
        {
            scanf("%d %d",&mem[i].a,&mem[i].b);
        }
        scanf("%d",&H);
        sort(mem+1,mem+n+1,cmp);//根据身高+臂长 从小到大排序
        L[n+1]=0;
        for(int i=n;i>=1;--i)
        L[i]=L[i+1]+mem[i].a;//从数组后面开始累加身高的和

        memset(ans,-1,sizeof(ans));
        for(int i=n;i>=0;--i)
        {
            if(dp(n,i)>=0)
            {
                printf("%d\n",i);//满足要求的最大 逃出人数
                break;
            }
        }
    }
    return 0;
}

  

 

posted on 2012-07-27 20:58  夜->  阅读(336)  评论(1编辑  收藏  举报