1430:家庭作业
【题目描述】
老师在开学第一天就把所有作业都布置了,每个作业如果在规定的时间内交上来的话才有学分。每个作业的截止日期和学分可能是不同的。例如如果一个作业学分为10,要求在6天内交,那么要想拿到这10学分,就必须在第6天结束前交。
每个作业的完成时间都是只有一天。例如,假设有7次作业的学分和完成时间如下:
| 作业号 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 期限 | 1 | 1 | 3 | 3 | 2 | 2 | 6 |
| 学分 | 6 | 7 | 2 | 1 | 4 | 5 | 1 |
最多可以获得15学分,其中一个完成作业的次序为2,6,3,1,7,5,4,注意可能d还有其他方法。
你的任务就是找到一个完成作业的顺序获得最大学分。
【输入】
第一行一个整数N,表示作业的数量。
接下来N行,每行包括两个整数,第一个整数表示作业的完成期限,第二个数表示该作业的学分。
【输出】
输出一个整数表示可以获得的最大学分。保证答案不超过longint范围。
【输入样例】
7 1 6 1 7 3 2 3 1 2 4 2 5 6 1
【输出样例】
15
【题目思路】
思路其实很简单,就是先按照学分从大到小排序,相等的按完成期限从小到大排序。然后找一个辅助数组,从这个学分的期限开始找,如果这个期限没有人占,那么之间加上这个学分,如果这个期限被占了(被其它的作业占了),就往前找,一直找到没有被占的期限。思路是很简单的,但是算法不行,如果采用暴力法,那会超时,所以要采用并查集来找。
并查集资料:https://www.cnblogs.com/cyjb/p/UnionFindSets.html
1 #define _CRT_SECURE_NO_WARNINGS 2 #define N 1000010 3 #include <iostream> 4 #include <algorithm> 5 #include <cstdio> 6 using namespace std; 7 int fz[N]; 8 int flag; 9 typedef struct My { 10 int time; 11 int score; 12 }Stu; 13 14 bool cmp(Stu a, Stu b) { 15 if (a.score != b.score) { 16 return a.score > b.score; 17 } 18 else { 19 return a.time < b.time; 20 } 21 } 22 23 void init() { //初始化,将父结点指向自己 24 for (int i = 0; i < N; i++) //注意这里是最大值N,不是作业的数量n 25 { 26 fz[i] = i; 27 } 28 } 29 30 int find(int a) { //找到空的时间点(期限) 31 if (a <= 0) { 32 return a; 33 } 34 else if (fz[a] == a) { 35 fz[a] = a - 1; 36 flag = 1; 37 return fz[a]; 38 } 39 else { 40 return fz[a] = find(fz[a]); 41 } 42 } 43 44 int main() 45 { 46 int n, sum = 0; 47 static Stu stu[1000010]; 48 scanf("%d", &n); 49 for (int i = 0; i < n; i++) 50 { 51 scanf("%d%d", &stu[i].time, &stu[i].score); 52 } 53 sort(stu, stu + n, cmp); 54 init(); 55 int i = 0; 56 while (i < n) { 57 flag = 0; 58 find(stu[i].time); 59 if (flag) { 60 sum += stu[i].score; 61 } 62 i++; 63 } 64 printf("%d", sum); 65 return 0; 66 }

浙公网安备 33010602011771号