BZOJ 3174: [Tjoi2013]拯救小矮人
Description
一群小矮人掉进了一个很深的陷阱里,由于太矮爬不上来,于是他们决定搭一个人梯。即:一个小矮人站在另一小矮人的 肩膀上,知道最顶端的小矮人伸直胳膊可以碰到陷阱口。对于每一个小矮人,我们知道他从脚到肩膀的高度Ai,并且他的胳膊长度为Bi。陷阱深度为H。如果我 们利用矮人1,矮人2,矮人3,。。。矮人k搭一个梯子,满足A1+A2+A3+....+Ak+Bk>=H,那么矮人k就可以离开陷阱逃跑了,一 旦一个矮人逃跑了,他就不能再搭人梯了。
我们希望尽可能多的小矮人逃跑, 问最多可以使多少个小矮人逃跑。
Input
第一行一个整数N, 表示矮人的个数,接下来N行每一行两个整数Ai和Bi,最后一行是H。(Ai,Bi,H<=10^5)
Output
一个整数表示对多可以逃跑多少小矮人
Sample Input
样例1
2
20 10
5 5
30
样例2
2
20 10
5 5
35
2
20 10
5 5
30
样例2
2
20 10
5 5
35
Sample Output
样例1
2
样例2
1
2
样例2
1
HINT
数据范围
30%的数据 N<=200
100%的数据 N<=2000
题解:
这个题目,首先我们肯定会想出很多贪心吧!然而每一个贪心都……其中有一个贪心是这样的,按照Ai+Bi排序,然后先看小的,如果可以走就走,但这个贪心是有问题的,就是假如有一个人,他本来可以走,但是如果他不走可以多挽救>1个人,那么显然他不走更优秀。所以这个东西是需要决策的,判断这个人十分让他走,但这个贪心有一定的可取只出。就是你走的顺序,一定是按照你排序后的顺序来走到,即:如果将排序后的人重新编号,那么走的顺序一定是类似于1,3,5这样的递增序列,而不是3,1,5这样的。
所以这个问题就转化成了,一个01背包的变种问题,我们考虑设dp[i]表示走了i个人的剩余人的最大高度,那么决策就是第i个人走或者不走。因为可能剩下的高度为0,所以初始化要为-1,这个题目猜到那个结论,有知道要dp就不难了。
代码:
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #include <cmath> #include <iostream> #define MAXN 30000 using namespace std; int dp[MAXN]; struct people{ int hi,shou; }a[MAXN]; int n,dep; bool cmp(people x,people y){ return x.hi+x.shou<y.hi+y.shou; } int main() { scanf("%d",&n);int sum=0; for(int i=1;i<=n;i++){ scanf("%d%d",&a[i].hi,&a[i].shou); sum+=a[i].hi; } sort(a+1,a+n+1,cmp); memset(dp,-1,sizeof(dp)); dp[0]=sum;int h=0; scanf("%d",&dep); for(int i=1;i<=n;i++){ for(int j=h;j>=0;j--){ if(dp[j]+a[i].shou>=dep) dp[j+1]=max(dp[j+1],dp[j]-a[i].hi); if(dp[j+1]>=0) h=max(h,j+1); } } printf("%d",h); return 0; }