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; }