【贪心】家庭作业

题目描述
老师在开学第一天就把所有作业都布置了,每个作业如果在规定的时间内交上来的话才有学分。每个作业的截止日期和学分可能是不同的。例如如果一个作业学分为10,要求在6天内交,那么要想拿到这10学分,就必须在第6天结束前交。
每个作业的完成时间都是只有一天。例如,假设有7次作业的学分和完成时间如下:

老师在开学第一天就把所有作业都布置了,每个作业如果在规定的时间内交上来的话才有学分。每个作业的截止日期和学分可能是不同的。例如如果一个作业学分为10,要求在6天内交,那么要想拿到这10学分,就必须在第6天结束前交。
每个作业的完成时间都是只有一天。例如,假设有7次作业的学分和完成时间如下:

输入
第一行一个整数N,表示作业的数量;
接下来N行,每行包括两个整数,第一个整数表示作业的完成期限,第二个数表示该作业的学分。

输出
输出一个整数表示可以获得的最大学分。保证答案不超过C/C++的int范围。

样例输入
复制样例数据
7
1 6
1 7
3 2
3 1
2 4
2 5
6 1
样例输出
15

提示
对于20%的数据,N≤103;
对于40%的数据,N≤104;
对于60%的数据,N≤105;
对于100%的数据,N≤106,作业的完成期限均小于7×105

思路分析:按照贪心策略来,一定会把学分高的放在前面,然后进行遍历,能写的科目就写,最后得到的答案一定是最优解.但此题的问题是如何确定目前科目前是否还有空天并把它找出来,楼主之前是想用一个标记数组以及while(i–)挨个遍历,没错,TLE了…然后接触了并查集这个玩意----另用一个指向数组并将一个数指向它前一个数,然后用函数调用,如果这个数是空就用它,否则就往前推直到找到下一个空的数,再将标记指向它,下次在用它是就不用一个个找了.

附代码:

#include<iostream>
#include<algorithm>
using namespace std;
typedef struct homework
{
	int timelimit, score;
}Homework;
int numb[(int)(1e6 + 5)];				//标记数组
int before[(int)(1e6 + 5)];				//指向数组(指向前面第一个空天)
Homework hw[(int)(1e6 + 5)];
int cmp(Homework a, Homework b)
{
	if (a.score == b.score)
		return a.timelimit < b.timelimit;
	else
		return a.score > b.score;
}
int unon(int n)
{
	if (!numb[n])						//定义0为空天,如果这天是空的就直接返回这天
		return n;
	else 
	{
		before[n] = unon(before[n]);		//否则就往前走直到找到空天
		return unon(before[n]);
	}
}
int main()
{
	int n;
	while (~scanf("%d", &n))
	{
		for (int i = 1; i <= n; i++)
		{
			scanf("%d%d", &hw[i].timelimit, &hw[i].score);
			before[i] = i-1;
		}
		sort(hw+1, hw+1 + n, cmp);			//将每门学科按照学分排序
		memset(numb, 0, n * sizeof(int));		
		int sum = 0;
		for (int i = 1; i <= n; i++)
		{
			int yet = unon(hw[i].timelimit);
			if (yet)
			{
				numb[yet] = 1;
				sum += hw[i].score; 
				if (yet != hw[i].timelimit)					//实现指向最前面的空天
					before[hw[i].timelimit] = before[yet];
			}
		}
		printf("%d\n", sum);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_30253757/article/details/84865671