题意
工程师要安装n个服务,其中服务Ji需要si单位的安装时间,截止时间为di。超时会有惩罚值,若实际完成时间为ci,则惩罚值为max{0,ci-di}。从0时刻开始执行任务,问惩罚值最大的两个服务的惩罚值之和的最小是多少?
分析
乍一看似乎要二分,但实际上并不是。贪心来做,按di从小到大安排任务,当di相等时,让完成时间短的排前,这样安排任务一定时更优的,但是并不能满足题目的要求。于是需要从两个最大惩罚值的前面挑选一个任务,并将它放置在后面,然后更新答案即可。
#include<cstdio> #include<algorithm> using namespace std; #define maxn 510 struct Task{ int s, d; bool operator <(const Task t) const{ if(t.d == d) return s < t.s; else return d < t.d; } }T[maxn]; int pos, n; int solve(int cur) { int MAX1 = 0, MAX2 = 0, sum = 0; for(int i = 0; i <= pos; i++) { if(i == cur) continue; sum += T[i].s; if(sum - T[i].d >= MAX2) MAX2 = sum - T[i].d; if(MAX2 > MAX1) swap(MAX1,MAX2); } sum += T[cur].s; if(sum - T[cur].d >= MAX2) MAX2 = sum - T[cur].d; if(MAX2 > MAX1) swap(MAX1,MAX2); for(int i = pos + 1; i < n; i++) { sum += T[i].s; if(sum - T[i].d >= MAX2) MAX2 = sum - T[i].d; if(MAX2 > MAX1) swap(MAX1,MAX2); } return MAX2 + MAX1; } int main() { int test; scanf("%d",&test); while(test--) { scanf("%d",&n); for(int i = 0; i < n; i++) scanf("%d%d",&T[i].s, &T[i].d); sort(T,T+n); int cur = 0, MAX1 = 0, MAX2 = 0, t = 0; for(int i = 0; i < n; i++) { cur += T[i].s; if(cur - T[i].d >= MAX2) { MAX2 = cur - T[i].d; pos = i; } if(MAX2 > MAX1) swap(MAX1,MAX2); } int ans = MAX1 + MAX2; for(int i = 0; i < pos; i++) ans = min(ans,solve(i)); printf("%d\n",ans); } return 0; }