题意:有n个任务,每个任务都有完成时间和完成期限,惩罚值就是超出期限的时间,问所有任务完成的最大和第二大惩罚值之和最小是多少。
题解:先排序,期限越小的排前面,否则就时间短的先完成,但只这样不一定是最优解,可以牺牲某个任务使最终解更优,所以将牺牲掉任务的位置放到之前得到的第二大惩罚值的前面,这样可以使最大惩罚值减小,遍历之前的所有任务,更新最小值。
#include <stdio.h>
#include <algorithm>
using namespace std;
const int N = 505;
struct Work {
int s, d;
}w[N];
int n, pos;
int cmp(Work a, Work b) {
if (a.d != b.d)
return a.d < b.d;
return a.s < b.s;
}
int solve(int x) {
int max1 = 0, max2 = 0, t = 0;
for (int i = 0; i <= pos; i++) {
if (i == x)
continue;
t += w[i].s;
int k = max(0, t - w[i].d);
max2 = max(max2, k);
if (max2 > max1)
swap(max1, max2);
}
t += w[x].s;
int k = max(0, t - w[x].d);
max2 = max(max2, k);
return max1 + max2;
}
int main() {
int t;
scanf("%d", &t);
while (t--) {
scanf("%d", &n);
for (int i = 0; i < n; i++)
scanf("%d%d", &w[i].s, &w[i].d);
sort(w, w + n, cmp);
int max1 = 0, max2 = 0, t = 0;
for (int i = 0; i < n; i++) {
t += w[i].s;
if (t - w[i].d >= max2) {
pos = i;
max2 = t - w[i].d;
}
if (max2 > max1)
swap(max1, max2);
}
int res = max1 + max2;
for (int i = 0; i < pos; i++)
res = min(res, solve(i));
printf("%d\n", res);
}
return 0;
}