BZOJ3174: [Tjoi2013]拯救小矮人

题目大意: 每个小矮人有臂长和身高,它们可以搭人梯,如果人梯的人高度总和+最上面的人的手的高度>=H,那最上面的人就可以跑,跑了的人不能再搭人梯,问最多能跑几个小矮人


这题...做了好长好长时间啊

貌似从2015年就开始做了,但是当时写了个贪心不对,然后又上网搜题解没看懂,瞎改DP也不对,过了几个月重新做也是WA,今天突然心血来潮写一发就A了...

首先是要按照身高+臂长来排序,但是为什么呢?这个我看了很多题解都没看懂

大概证明如下:

考虑对于最上面的两个人,下面的人梯高度一定

如果无论怎样都出不去,那相对顺序肯定是无所谓的

如果怎么都能出去,那相对顺序肯定也是无所谓的

关键就是剩下的情况,两个人都有机会逃出去,但是排的先后顺序会影响逃跑结果

这种情况下就只能让身高+臂长比较小的人较先离开,因为他的逃生能力比较弱

但是对吗?


随之而来的又有一个问题,只贪心到底行不行

显然是不行的,比如一个高个短手,一个矮个长手,后面的加起来更大,结果先让前面的跑了,后面的跑不出去了,留下来的人还矮

这怎么办呢?

这时我们就发现“这种情况下就只能让身高+臂长比较小的人较先离开,因为他的逃生能力比较弱”这句话是错的

但是它为我们提供了一个思路,那就是最终的最优逃出方案一定可以是一个按照“身高+臂长”递增的序列

这个怎么证呢?就是当我们发生上述冲突时,我们肯定是选择让高个的留下并且永远留下,矮个那个先走,这样就满足了性质

然后就可以DP了!


所以!!我们排序+DP的原因不是XX放在XX前面一定更优,而是最终的逃跑序列一定是一个“身高+臂长”递增的序列,为了方便DP,所以我们才要排序!!!!


从2015-05-15 WA到 2016-06-16

一年一个月零一天


#include
#include
#include
#include
#define N 2010
using namespace std;
struct ppp{int a,b;}c[N];
bool cmp(ppp x,ppp y)
{
	return x.a+x.b=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;
	}
}

你可能感兴趣的:(BZOJ,DP,省选)