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;
}
                    
                
                
            
        
浙公网安备 33010602011771号