先考虑如果知道破坏碉堡顺序,我们考虑如何最优
显然令f[i]表示一开始有i的能力的最优非常不方便转移
我们考虑令f[i]表示破坏i个碉堡需要的最小能力值,f[0]=0
那么,f[i]=f[i-1]+A[j](B[j]>=f[i-1]) O(N^2)暴力做即可,最后二分出最大的i满足f[i]<=S
好的现在来考虑如何排序
考虑两个状态i,i+1
i和i+1不能交换的充分条件:b[i+1]<a[i]+Σa[j] (j>i+1)
同时我们还有条件b[i]>=a[i+1]+Σa[j] (j>i+1)
两式相减得到:b[i+1]-b[i]<a[i]-a[i+1]
b[i+1]+a[i+1]<a[i]+b[i]
所以我们只需要按照a[i]+b[i]的顺序排序即可
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; int n,m,f[1010]; struct p{ int a,b; } s[1010]; inline bool c1(p a,p b){ return a.a+a.b>b.a+b.b; } int _18520(){ if(~scanf("%d",&n)){ for(int i=n;i;--i) scanf("%d %d",&s[i].a,&s[i].b); sort(s+1,s+1+n,c1); memset(f,0x3f,sizeof f); f[0]=0; for(int i=n;i;--i) for(int j=n;j;--j) if(s[i].b>=f[j-1]) f[j]=min(f[j],f[j-1]+s[i].a); scanf("%d",&m); for(int t=n;~t;--t) if(f[t]<=m) return printf("%d\n",t); } return 0; } int main(){ while(_18520()); }