【贪心】家庭作业
题目描述
老师在开学第一天就把所有作业都布置了,每个作业如果在规定的时间内交上来的话才有学分。每个作业的截止日期和学分可能是不同的。例如如果一个作业学分为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;
}