HDU 1789 - Doing Homework again - [贪心+优先队列]

时间:2021-03-20 19:53:21

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1789

Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)

Problem Description
Ignatius has just come back school from the 30th ACM/ICPC. Now he has a lot of homework to do. Every teacher gives him a deadline of handing in the homework. If Ignatius hands in the homework after the deadline, the teacher will reduce his score of the final test. And now we assume that doing everyone homework always takes one day. So Ignatius wants you to help him to arrange the order of doing homework to minimize the reduced score.

Input
The input contains several test cases. The first line of the input is a single integer T that is the number of test cases. T test cases follow.
Each test case start with a positive integer N(1<=N<=1000) which indicate the number of homework.. Then 2 lines follow. The first line contains N integers that indicate the deadlines of the subjects, and the next line contains N integers that indicate the reduced scores.

Output
For each test case, you should output the smallest total reduced score, one line per test case.

Sample Input
3
3
3 3 3
10 5 1
3
1 3 1
6 2 3
7
1 4 6 4 2 4 3
3 2 1 7 6 5 4

Sample Output
0
3
5

本题作为一道比较基础的贪心题,在很久之前就做过了,具体请看博文http://www.cnblogs.com/dilthey/p/6804173.html

那为什么今天还要再做一遍呢,因为昨天参加校赛看到一道贪心题,和这道题目比较类似;

但是那道题目因为deadline非常大,不能像这题一样,开个标记数组,往前遍历;

所以就有了另一种解法(另一种贪心思路)。

解法:

考虑每天我们能做一样作业,所以我们用一个for循环+优先队列来模拟每天做作业的情况;

首先,根据贪心思想,我们越早做那些deadline比较早的作业比较好,因此我们先把所有作业按照deadline从小到大排序(复杂度O( n * log n ));

然后,我们构建一个存储作业的优先队列Heap(按照作业的扣分从小到大排列),用它的size()表示当前的日期;

对排序后的作业进行遍历,会遇到如下一些情况:

①作业的deadline大于Heap.size(),表示我们可以在今天("Heap.size()+1"这一天)做这项作业;

 因此,push入Heap即可。

②作业的deadline小于等于Heap.size(),表示这项作业hw[i]我们只能在 "1~Heap.size()" 这些天里完成,那么又会遇到两种情况:

 先取出Heap.top(),由于我们按照作业的扣分从小到大维护这个优先队列,所以堆顶部的是:已完成的、扣分最少的那项作业;

  1)hw[i].reduced_score > Heap.top().reduced_score,也就是说,我们还是做hw[i]更划算(扣的分更少),所以我们将用hw[i]替换掉Heap.top();

    这时,显然Heap.top()属于是“被抛弃的作业”,不可能再被完成了,所以ans += Heap.top().reduced_score

  2)hw[i].reduced_score <= Heap.top().reduced_score,显然,这时我们要放弃的作业就是hw[i]了;

    同样的,ans += hw[i].reduced_score;

最后,输出ans即可。

AC代码:

#include<bits/stdc++.h>
using namespace std;
struct Hw{
int dl,rs;//截止日期,会扣的分数
bool operator < (const Hw& oth)const{return oth.rs<rs;}
}hw[];
bool cmp(Hw a,Hw b){return a.dl<b.dl;}
int n;
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=;i<n;i++) scanf("%d",&hw[i].dl);
for(int i=;i<n;i++) scanf("%d",&hw[i].rs);
sort(hw,hw+n,cmp);
//for(int i=0;i<n;i++) printf("%d %d\n",hw[i].dl,hw[i].rs); priority_queue<Hw> heap;
int ans=;
for(int i=;i<n;i++)
{
if(hw[i].dl>heap.size()) heap.push(hw[i]);
else
{
//printf("now heap.top = %d,%d\n",heap.top().dl,heap.top().rs);
if(hw[i].rs>heap.top().rs)
{
ans+=heap.top().rs;
heap.pop();
heap.push(hw[i]);
}
else ans+=hw[i].rs;
}
} printf("%d\n",ans);
}
}

(PS.其实实际上,heap不需要把整个作业都存进去,单单维护int类型的reduced_score也是完全可以的,不过为了说起来清晰明了一些,就维护了Hw);

最后,

HDU 1789 - Doing Homework again - [贪心+优先队列]

比对一下之前用的基础贪心做法和这次的优化后的做法,可以明显地看到时间空间复杂度的降低;