题目大意: 每个小矮人有臂长和身高,它们可以搭人梯,如果人梯的人高度总和+最上面的人的手的高度>=H,那最上面的人就可以跑,跑了的人不能再搭人梯,问最多能跑几个小矮人
这题...做了好长好长时间啊
貌似从2015年就开始做了,但是当时写了个贪心不对,然后又上网搜题解没看懂,瞎改DP也不对,过了几个月重新做也是WA,今天突然心血来潮写一发就A了...
首先是要按照身高+臂长来排序,但是为什么呢?这个我看了很多题解都没看懂
大概证明如下:
考虑对于最上面的两个人,下面的人梯高度一定
如果无论怎样都出不去,那相对顺序肯定是无所谓的
如果怎么都能出去,那相对顺序肯定也是无所谓的
关键就是剩下的情况,两个人都有机会逃出去,但是排的先后顺序会影响逃跑结果
这种情况下就只能让身高+臂长比较小的人较先离开,因为他的逃生能力比较弱
但是对吗?
随之而来的又有一个问题,只贪心到底行不行
显然是不行的,比如一个高个短手,一个矮个长手,后面的加起来更大,结果先让前面的跑了,后面的跑不出去了,留下来的人还矮
这怎么办呢?
这时我们就发现“这种情况下就只能让身高+臂长比较小的人较先离开,因为他的逃生能力比较弱”这句话是错的
但是它为我们提供了一个思路,那就是最终的最优逃出方案一定可以是一个按照“身高+臂长”递增的序列
这个怎么证呢?就是当我们发生上述冲突时,我们肯定是选择让高个的留下并且永远留下,矮个那个先走,这样就满足了性质
然后就可以DP了!
所以!!我们排序+DP的原因不是XX放在XX前面一定更优,而是最终的逃跑序列一定是一个“身高+臂长”递增的序列,为了方便DP,所以我们才要排序!!!!
从2015-05-15 WA到 2016-06-16
一年一个月零一天
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 2010
using namespace std;
struct ppp{int a,b;}c[N];
bool cmp(ppp x,ppp y)
{
return x.a+x.b<y.a+y.b;
}
int f[N][N];
int hou[N];
int main()
{
int n,H;
scanf("%d",&n);
int i,j;
for(i=1;i<=n;i++)
scanf("%d%d",&c[i].a,&c[i].b);
scanf("%d",&H);
sort(c+1,c+n+1,cmp);
for(i=n;i>=1;i--)
hou[i]=hou[i+1]+c[i].a;
memset(f,0xef,sizeof(f));
f[0][0]=0;
for(i=1;i<=n;i++)
{
for(j=i;j>=0;j--)
{
f[i][j]=f[i-1][j]+c[i].a;
if(j&&f[i-1][j-1]+c[i].a+c[i].b+hou[i+1]>=H) f[i][j]=max(f[i-1][j-1],f[i][j]);
}
}
for(i=n;i>=0;i--)
if(f[n][i]>=0)
{
printf("%d",i);
return 0;
}
}