概述
题目链接
贪心,优先队列。
题意:
给了
n
n
n个任务的结束时间和奖励,让我们安排做任务的顺序,使最终能够得到的奖励最大。
题解:
朴素做法:
首先将所有的任务根据奖励的大小从大到小排序,如果奖励大小相同,结束时间晚的排在前面。贪心的策略就是,将该任务结束时间前第一个没有被安排任务的时间分给该任务。由于结束时间的数据较大,直接贪心会出错,我们发现,总共只有
n
n
n个任务,也就是最多只需要
n
n
n个单位的时间就可以做完所有任务。因此,我们在贪心时,将当前任务的结束时间与
n
n
n取一个
m
i
n
min
min。
朴素版代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 5e4 + 10;
bool flag[MAXN];
struct P {
ll e, w;
}p[50010];
bool cmp(P a, P b) {
if (a.w == b.w) {
return a.e > b.e;
}
return a.w > b.w;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
ll n;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> p[i].e >> p[i].w;
}
sort(p, p + n, cmp);
ll ans = 0;
for (int i = 0; i < n; i++) {
ll pos = p[i].e;
pos = min(pos, n); // 最多用n个单位时间
while (pos && flag[pos]) pos--; // 找到结束时间之前第一个没有任务的时间
if (pos) {
flag[pos] = true;
ans += p[i].w;
}
}
cout << ans << endl;
return 0;
}
优化一点的版本是贪心+优先队列。
首先将所有的任务按照结束时间从早到晚排序。然后判断每个任务是否插入优先队列当中。如果当前任务的结束时间晚于队列的长度,也就是已经耗费的时间。那么将该任务的奖励直接加入队列,同时答案加上该任务奖励。如果,早于当前队列的长度,那么我们先将该任务加入队列,然后将队列当中奖励最少的任务拿出。
这样最终队列当中的任务奖励总和就是答案。时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)。
优化版代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 5e4 + 10;
bool flag[MAXN];
priority_queue<int, vector<int>, greater<int> > q;
struct P {
ll e, w;
}p[50010];
bool cmp(P a, P b) {
return a.e < b.e;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
ll n;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> p[i].e >> p[i].w;
}
sort(p, p + n, cmp);
ll ans = 0;
for (int i = 0; i < n; i++) {
if (p[i].e > q.size()) { // 晚于已经花费的时间,直接加入队列
ans += p[i].w;
q.push(p[i].w);
}
else { // 早于已花费时间,替换队列中奖励最少的任务
ans += p[i].w;
q.push(p[i].w);
ans -= q.top();
q.pop();
}
}
cout << ans << endl;
return 0;
}
并查集版本:
先将所有的任务按照奖励降序排序,然后使用并查集依次判断是否有当前任务可用的时间点。
我们使用并查集维护当前未使用的时间点,其中
f
[
x
]
=
a
f[x]=a
f[x]=a表示结束时间为
x
x
x的任务可以在时间点
a
a
a完成。
时间复杂度是 O ( N a ( N ) ) O(Na(N)) O(Na(N)), a ( N ) a(N) a(N)是并查集的查找过程,接近于1。
并查集版代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 5e4 + 10;
int f[MAXN];
struct P {
ll e, w;
}p[50010];
bool cmp(P a, P b) {
return a.w > b.w;
}
int find(int x) {
if (x <= 0) return -1;
if (f[x] == x) {
return f[x] = x - 1; // 当前时间点可用
}
else {
return f[x] = find(f[x]);
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
ll n;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> p[i].e >> p[i].w;
f[i] = i;
}
sort(p, p + n, cmp);
ll ans = 0;
for (int i = 0; i < n; i++) {
if (find(p[i].e) >= 0) { // 查找是否存在可用的时间点
ans += p[i].w;
}
}
cout << ans << endl;
return 0;
}
最后
以上就是喜悦蜜蜂为你收集整理的51nod 1163 最高的奖励的全部内容,希望文章能够帮你解决51nod 1163 最高的奖励所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复