Time Limits: 1000 ms Memory Limits: 128000 KB Detailed Limits
Description
张辽是一个长发飘飘的非常聪明的男孩,人人都称他为“辽哥”。辽哥喜欢玩一个有趣的电脑游戏。这个游戏开始的时候有n个碉堡,每个碉堡拥有一个防御值和一个附加值。玩家拥有一个初始的攻击力。如果玩家破坏了一个碉堡,则他能得到1分。每一次,辽哥会选择一个碉堡进行攻击。所有未被破坏的碉堡会联合起来防御,因此为了破坏那个碉堡,辽哥的攻击力必须大于或者等于所有未被破坏的碉堡的防御值之和,否则辽哥就会输掉游戏。如果辽哥成功破坏了那个碉堡,那么他的攻击力会变成那个碉堡的附加值,然后他可以选择下一个攻击的目标。
由于辽哥拥有强大的编程能力,他不费吹灰之力就改写了那个游戏。在游戏开始前,他可以用炸弹消灭任意的碉堡,但是他不能通过这种方式来获得分数。问题来了,在游戏开始后,辽哥可以得到的最大分数是多少?
Input
输入包含多组(不超过100组)测试数据。
每组测试数据的第一行包含一个正整数N,表示测碉堡的数目。接下来有N行,每行包括2个非负整数。第i+1行的2个整数分别表示第i个碉堡的防御值和附加值。最后还有一行,为一个整数,表示辽哥在游戏开始时的初始攻击力。
输入以文件结束符结束。
Output
对每组数据,输出一行,为一个整数,表示辽哥可以拿到的最大分数。
Sample Input
3
10 9
25 30
8 7
50
5
100 230
334 331
33 288
35 100
334 22
600
Sample Output
3
4
Data Constraint
Hint
【数据范围】
对20%的数据,有N<=10;
对40%的数据,有N<=100;
对100%的数据,有N<=1000,每个碉堡的防御值和附加值均不会超过2000000。
Source / Author: liao
可以炸掉一些就是可以不选一些。
设F[i] 为选i个碉堡时的最小防御和。
答案就是最大的m使f[m] <= 初始攻击
f[i] = MIn{f[i] , f[i-1] + a[j]} (b[j] >= f[i-1])
最优的转移,就是让f[i-1]开始尽量小 , 就有更多满足b[j] >= f[i-1] , 更优。
考虑排序a【】,b【】
设前边的防御和g
i < j ,若i要和j交换:
『
1 . g+a[i] > b[j]
2 . g + a[j] < = b[i]
』
2 . b[i]>= g + a[j]
+『1』
b[i] + g + a[i] >= g + a[j]+b[j]
消掉g,就可以排序了
#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long
#define N 2010
#define open(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout);
#define INF 2147483647
using namespace std;
struct pillbox
{
int d,a;
}p[N];
int n,c,i,j,t,ans;
int f[N];
bool cmp(pillbox b,pillbox a)
{
return a.a + a.d < b.a + b.d;
}
void dp()
{
mem(f,127);
f[0]=0;
for(j=n;j;j--)
for(i=n;i;i--)
{
if(p[j].a >= f[i-1])f[i] = min(f[i] , f[i-1] + p[j].d);
}
return ;
}
void findans()
{
ans=0;
for(i=n;i;i--) if(f[i] <= c)
{
ans = i;
return ;
}
return ;
}
int main()
{
while(~scanf("%d",&n))
{
for(i=1;i<=n;i++)scanf("%d%d",&p[i].d,&p[i].a);
sort(p+1,p+1+n,cmp);
ans = 0;
scanf("%d",&c);
dp();
findans();
printf("%d\n",ans);
}
return 0;
}
O(n^2)