HDU 1789-Doing Homework again(并查集+贪心)

Doing Homework again

Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 22901 Accepted Submission(s): 13208

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

问题描述
Ignatius刚从第30届ACM / ICPC重返学校。现在他有很多作业要做。每个老师都给他交作业的最后期限。如果Ignatius在截止日期之后交作业,则老师会降低其最终考试的分数。现在,我们假设每个人都要做一天的功课。因此,伊格纳修斯(Ignatius)希望您帮助他安排家庭作业的顺序,以最大程度地降低分数。

输入值
输入包含几个测试用例。输入的第一行是单个整数T,它是测试用例的数量。随后是T测试用例。
每个测试用例都以一个正整数N(1 <= N <= 1000)开头,该正整数表示作业的数量。然后是2行。第一行包含N个整数,它们指示受试者的截止日期,而第二行包含N个整数,指示分数的降低。

输出量
对于每个测试用例,您应该输出最小的总减少分数,每个测试用例一行。

样本输入
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

样本输出
0
3
5

题目链接

题目大意:首先给出T组测试样例,对于每个测试样例:给出n门作业,接下来有两行,第一行是第 i 个作业的截止日期,第二行是第 i 个作业的成绩,我们要求的是在最后一门功课截止后最小的扣除分数。样例二解释:有成绩为6 2 3的三门功课,截止日期都是1 3 1天,我们可以看到在截止日期为1的时候有两门功课,分别是6 和 3 为了使最后的分数尽可能高,即减少的分数越少,我们选择在第一天完成成绩为 6 的作业,第二天或第三天完成成绩为2的作业,这样满分是6+2+3=11分,但是我们最后能得到6+2=8分,所以我们最后最少可以扣除11-8=3分。

解题思路:这道题我用到的是贪心+并查集,因为一天之内可能有好几种作业,我们如果每一天都选择分数最高的作业来完成,最后扣除的分数一定是最小的。设一个结构体数组,存放截止日期和作业的分数,按分数排序,因为我们可以在截止日期内的任意一天完成作业,所以我们原则上选择截止日期的最后一天,如果这一天被占用了则选择这一天的前一天(因为按分数从大到小,所以这一天的得到的一定是最高的),举个栗子:如果价值最高的为10,截止日期为2,那么在第二天完成10分的作业,第二天被占用,价值第二高的分数为9,但截止日期也是2,我们可以看到第二天已经要完成分数为10的作业了,所以继续往前推,第一天没有被占用则在第一天完成。AC代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int _max=1e3+50;
struct node {int d,g;};
bool cmp(node a,node b) {return a.g>b.g;};//g为分数,d为截止日期
int f[_max];
node a[_max];
int getf(int x)
{
	if(f[x]!=-1)//并查集寻根,判断哪一天是没有被占用的
	  return f[x]=getf(f[x]);
	return x;
}
int main()
{
	ios::sync_with_stdio("false");
	int t;
	cin>>t;
	while(t--)
	{
		int n;
		cin>>n;
		for(int i=0;i<n;i++)
		  cin>>a[i].d;
		for(int i=0;i<n;i++)
		  cin>>a[i].g;
		sort(a,a+n,cmp);
		int sum1=0,sum2=0;
		for(int i=0;i<n;i++)
		  sum1+=a[i].g;//求满分
		memset(f,-1,sizeof f);
		for(int i=0;i<n;i++)
		{
			int s=getf(a[i].d);
			if(s>0)
			{
				sum2+=a[i].g;
				f[s]=s-1;//这一天已经被占用了,所以往前推一天
			}
		}
		cout<<sum1-sum2<<endl;//满分减去当前的最高分就是ans
	}
	//system("pause");
	return 0;
}
原文地址:https://www.cnblogs.com/Hayasaka/p/14294296.html