可以反悔的贪心——贪心+堆维护

Posted sympa

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了可以反悔的贪心——贪心+堆维护相关的知识,希望对你有一定的参考价值。

P2949 [USACO09OPEN]Work Scheduling G

题目描述

Farmer John has so very many jobs to do! In order to run the farm efficiently, he must make money on the jobs he does, each one of which takes just one time unit.

His work day starts at time 0 and has 1,000,000,000 time units (!). He currently can choose from any of N (1 <= N <= 100,000) jobs

conveniently numbered 1..N for work to do. It is possible but

extremely unlikely that he has time for all N jobs since he can only work on one job during any time unit and the deadlines tend to fall so that he can not perform all the tasks.

Job i has deadline D_i (1 <= D_i <= 1,000,000,000). If he finishes job i by then, he makes a profit of P_i (1 <= P_i <= 1,000,000,000).

What is the maximum total profit that FJ can earn from a given list of jobs and deadlines? The answer might not fit into a 32-bit integer.

输入格式

* Line 1: A single integer: N

* Lines 2..N+1: Line i+1 contains two space-separated integers: D_i and P_i

输出格式

* Line 1: A single number on a line by itself that is the maximum possible profit FJ can earn.

 

输入输出样例

输入 #1
  3 
2 10 
1 5 
1 7 
输出 #1
17 

预备知识:
1.贪心算法
2.用STL优先队列实现堆
3.关系运算符重载

思路:
先了解题目大意,每个单位时间可以完成一项工作,但每项工作都有各自的过期时间,过期的工作不能选择,求最大利润。
很明显,这题用到了贪心的思想,要在所给的工作内,选择利润尽可能大的工作来完成。
来确定贪的方向:因为每项工作的耗时都是一个单位时间,所以想获得尽可能多的利润,要选择尽可能多的工作。
但是,如果在选择m分钟过期的工作时,自己的1-m的时间都已经被工作填满了,该怎么办?
很容易想到暴力的算法:从自己已经选择的期限为1-m的工作中,找到一个工作利润最低的和当前备选工作比较,如果备选工作的利润高,就将两者替换。
这么做的复杂度为O(n^2),那么,有没有更优的解法?使用堆来维护贪心的选择,可以使复杂度达到O(nlogn)。

做法:
首先用优先队列建立堆,重载<运算符,使得两工作之间按利润进行排序。读入工作后,让它们按过期时间从低到高排序,可以想想为什么。
遍历工作数组,堆大小小于当前工作的过期时间,工作入堆,否则与堆顶比较,如果当前工作利润高,两者交换。

代码:
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int n;
 4 struct node {
 5     int d, p;
 6     bool operator < (const node& x) const { return p > x.p; }
 7 };
 8 bool cmp(node d1, node d2) {
 9     if (d1.d == d2.d)return d1.p > d2.p;
10     else return d1.d < d2.d;
11 }
12 node a[100010];
13 int main() {
14     std::ios::sync_with_stdio(false);
15     priority_queue< node >q;
16     long long sum = 0;
17     cin >> n;
18     for (int i = 1; i <= n; i++) {
19         cin >> a[i].d >> a[i].p;
20     }
21     sort(a + 1, a + 1 + n, cmp);
22     for (int i = 1; i <= n; i++) {
23         if (a[i].d <= q.size()) {
24             if (a[i].p > q.top().p) {
25                 sum -= q.top().p;
26                 q.pop();
27                 sum += a[i].p;
28                 q.push(a[i]);
29             }
30         }
31         else {
32             sum += a[i].p;
33             q.push(a[i]);
34         }
35     }
36     cout << sum << endl;
37     return 0;
38 }

 

以上是关于可以反悔的贪心——贪心+堆维护的主要内容,如果未能解决你的问题,请参考以下文章

反悔贪心

可撤销贪心

可以反悔的贪心

P1484 种树(堆)

BZOJ1572: [Usaco2009 Open]工作安排Job

bzoj 2151: 种树贪心+堆