BZOJ_3174_[Tjoi2013]拯救小矮人_贪心+DP
Description
一群小矮人掉进了一个很深的陷阱里,由于太矮爬不上来,于是他们决定搭一个人梯。即:一个小矮人站在另一小矮人的 肩膀上,知道最顶端的小矮人伸直胳膊可以碰到陷阱口。对于每一个小矮人,我们知道他从脚到肩膀的高度Ai,并且他的胳膊长度为Bi。陷阱深度为H。如果我 们利用矮人1,矮人2,矮人3,。。。矮人k搭一个梯子,满足A1+A2+A3+....+Ak+Bk>=H,那么矮人k就可以离开陷阱逃跑了,一 旦一个矮人逃跑了,他就不能再搭人梯了。
我们希望尽可能多的小矮人逃跑, 问最多可以使多少个小矮人逃跑。
Input
Output
Sample Input
2
20 10
5 5
30
样例2
2
20 10
5 5
35
Sample Output
2
样例2
1
HINT
数据范围
30%的数据 N<=200
100%的数据 N<=2000
分析:
这道题其实是在求一个子序列。在某种方案下都能够逃跑的子序列中最长的一个。
我们先贪心地确定逃跑方案。
首先,对于两个一定要逃跑的人x和y,如果a[x]+a[y]<b[x]+b[y],说明x比y弱,不妨让x先逃跑。
于是我们可以按a+b排一下序。
然后找最长的子序列。设f[i][j]为前i个人,走了j个后最高的高度。
f[i][j]=f[i-1][j]; f[i][j]=max(f[i][j],f[i-1][j-1]-a[j])(b[j]+f[i-1][j-1]>=h)
代码:
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; #define N 2050 struct A { int a,b; }a[N]; int h,n,f[N][N]; bool cmp(const A &x,const A &y) { return x.a+x.b<y.a+y.b; } int main() { scanf("%d",&n); int i, ans=0, j; memset(f,-1,sizeof(f)); f[0][0]=0; for(i=1;i<=n;++i) scanf("%d%d",&a[i].a,&a[i].b),f[0][0]+=a[i].a; sort(a+1,a+n+1,cmp); scanf("%d",&h); for(i=0;i<n;++i) { f[i+1][0]=f[i][0]; for(j=0;j<=ans;j++) { f[i+1][j+1]=f[i][j+1]; if(f[i][j]+a[i+1].b>=h) { f[i+1][j+1]=max(f[i+1][j+1],f[i][j]-a[i+1].a); } } if(f[i+1][ans+1]>=0) ans++; } printf("%d\n",ans); }