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号