奥赛一本通 1426 智力大冲浪
1426 智力大冲浪
题目大意
有 $n$ 个任务,每个任务都有一个最晚的完成时间,如果未能完成则需要赔钱,求最少的赔钱数。
知识要点
贪心、排序、堆
解题思路 1
显然赔钱数越多的任务应该先保证完成,而它的完成时间则应该尽可能靠后,以便节省前面的时间完成更多任务。将所有任务根据赔钱数从大到小排序,每个任务都安排在要求时间前最晚的空闲时间即可,时间复杂度 $O(n^2)$。
参考代码 1
#include <bits/stdc++.h>
using namespace std;
struct Task {
int t, w;
} T[505];
bool cmp(Task A, Task B) {
return A.w > B.w;
}
bool f[505]; //记录空闲时间
int main() {
int m, n;
scanf("%d%d", &m, &n);
for(int i = 0; i < n; i++) scanf("%d", &T[i].t);
for(int i = 0; i < n; i++) scanf("%d", &T[i].w);
sort(T, T + n, cmp);
for(int i = 0; i < n; i++) {
int j = T[i].t;
while(j && f[j]) j--; //从后往前找到空闲时间
if(j) f[j] = 1;
else m -= T[i].w;
}
printf("%d\n", m);
return 0;
}
解题思路 2
从时间的角度考虑,越靠后的时间可完成的任务越少,因此选择赔钱数多的任务完成。将所有任务根据要求时间从后到前排序,随着时间往前回退,可以完成的任务越来越多,使用堆取出赔钱数最多的任务即可,时间复杂度 $O(n \log n)$。
参考代码 2
#include <bits/stdc++.h>
using namespace std;
struct Task {
int t, w;
} T[505];
bool cmp(Task A, Task B) {
return A.t > B.t;
}
int main() {
int m, n;
scanf("%d%d", &m, &n);
for(int i = 0; i < n; i++) scanf("%d", &T[i].t);
for(int i = 0; i < n; i++) scanf("%d", &T[i].w);
sort(T, T + n, cmp);
priority_queue<int> Q;
for(int i = 0, j = n; j ; j--) {
while(i < n && T[i].t == j) Q.push(T[i++].w); //加入当前时间可完成的任务
if(Q.size()) Q.pop(); //取出赔钱数最高的任务完成
}
while(Q.size()) m -= Q.top(), Q.pop();
printf("%d\n", m);
return 0;
}

浙公网安备 33010602011771号