工作安排

工作安排

题目地址: 2022/3/13

题目描述

约翰有太多的工作要做。

为了让农场高效运转,他必须靠他的工作赚钱,每项工作花一个单位时间。

他的工作日从 \(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;
}

posted @ 2022-03-13 21:50  ccz9729  阅读(69)  评论(0编辑  收藏  举报