工作安排
工作安排
题目描述
约翰有太多的工作要做。
为了让农场高效运转,他必须靠他的工作赚钱,每项工作花一个单位时间。
他的工作日从 \(0\) 时刻开始,有 \(10^9\) 个单位时间。
在任一时刻,他都可以选择编号 \(1\) 到 \(N\) 的 \(N\) 项工作中的任意一项工作来完成。
每项工作又有一个截止日期,对于第 \(i\) 个工作,有一个截止时间 \(D_i\),如果他可以完成这个工作,那么他可以获利 \(P_i\)。
在给定的工作利润和截止时间下,约翰能够获得的利润最大为多少。
数据范围: \(1 \le N \le 10^5 , 0 \le D_i, P_i \le 10^9\)
思路
注意到每个工作的工作时间都是 \(1\),因此对于某个时间,我们选最大的获利一定是最优的,那么我们考虑把所有的工作按照价值排序,从大到小枚举每一个工作,尽量选最靠近 \(P_i\) 的时间,这样才可以使其他的工作有更有可能被做。
因此我们可以用 并查集 快速的找到在 \(P_i\) 之间最近的没有被用过的时间。
CODE
#include <unordered_map>
#include <stdio.h>
#include <algorithm>
struct node {
int ddl, w;
bool operator < (const node &T) const {
return w > T.w;
}
}a[100010];
std::unordered_map<int, int> f; //由于值域太大,我们用 unordered_map 当做离散化后的并查集
int find(int x) {
if(!f.count(x)) f[x] = x;
if(f[x] != x) f[x] = find(f[x]);
return f[x];
}
int main() {
int n; scanf("%d", &n);
for(int i = 1; i <= n; i ++ ) {
scanf("%d%d", &a[i].ddl, &a[i].w);
}
std::sort(a + 1, a + 1 + n);
long long ans = 0;
for(int i = 1; i <= n; i ++ ) {
int k = find(a[i].ddl);
if(k <= 0) continue;
ans += a[i].w;
f[k] = k - 1;
}
printf("%lld\n", ans);
return 0;
}