奥赛一本通 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;
}
posted @ 2026-09-01 08:55  萧西待水  阅读(5)  评论(0)    收藏  举报