本文主要是介绍家庭作业 题解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
小编:真是一道有趣的题,通过量还不算低,我也就写写自己的想法
题目描述
老师在开学第一天就把所有作业都布置了,每个作业如果在规定的时间内交上来的话才有学分。每个作业的截止日期和学分可能是不同的。例如如果一个作业学分为10分,要求在6天内交,那么要想拿到这10学分,就必须在第6天结束前交。每个作业的完成时间都是只有一天。例如,假设有7次作业的学分和完成时间如下:
作业号 | 期限 | 学分 |
---|---|---|
1 | 1 | 6 |
2 | 1 | 7 |
3 | 3 | 2 |
4 | 3 | 1 |
6 | 2 | 5 |
7 | 6 | 1 |
最多可以获得15学分,其中一个完成作业的次序为2,6,3,1,7,5,4,注意可能还有其他方法。你的任务就是找到一个完成作业的顺序获得最大学分。
- 输入格式第一行一个整数N,表示作业的数量;接下来N行,每行包括两个整数,第一个整数表示作业的完成期限,第二个数表示该作业的学分。* 输出格式输出一个整数表示可以获得的最大学分。保证答案不超过 C/C++ 的 int 范围。
样例输入
7
1 6
1 7
3 2
3 1
2 4
2 5
6 1
样例输出
15
数据范围与提示
100% N <= 1000000;
分析
很明显这是一道贪心题,先做分值高的。实现起来就是:先按分值大小排序,再枚举空出来的时间,选择最靠后的,如果还有空出来的时间就说明这个作业能完成,累加最终的答案,这样一定能得到最优的解
STEP1
我尝试了一下暴力,这也是最容易想到的,最后以超时告终,拿到80分
#include <cstdio>
#include <algorithm>
using namespace std;const int MAXN = 1000005;
struct node {int t, v;
} a[MAXN];
bool flag[MAXN];bool cmp (node x, node y) { // 排序 cmp 函数if(x.v == y.v) return x.t < y.t;else return x.v > y.v;
}int main() {int n, ans = 0;scanf ("%d", &n);for(int i = 1; i <= n; i++) scanf ("%d %d", &a[i].t, &a[i].v);sort(a + 1, a + n + 1, cmp); for(int i = 1; i <= n; i++) {for(int j = a[i].t; j >= 1; j--) { // 倒着向前枚举if(flag[j] == false) {flag[j] = true; // 更新此时间为被占用ans += a[i].v; // 累加答案break; // 找到了就跳出}} } printf("%d", ans);return 0;
}
STEP2
并查集优化即可
模板:
void void Make_Set(int n) { // 初始化for(int i = 1; i <= n; i++) fa[i] = i; // 指向自己return ;
}int Find_Set(int x) { // 查询根结点 递归实现if(fa[x] != x) return fa[x] = Find_Set(fa[x]);else return fa[x];
}void Union_Set(int x, int y) { // 合并int u = Find_Set(x);int v = Find_Set(y);if(u != v) fa[v] = u;return ;
}
AC代码
#include <cstdio>
#include <algorithm>
using namespace std;const int MAXN = 1000005;
struct node {int t, v;
} a[MAXN];
bool flag;
int fa[MAXN];bool cmp (node x, node y) { // 排序 cmp 函数if(x.v == y.v) return x.t < y.t;else return x.v > y.v;
}void Make_Set(int n) { // 初始化for(int i = 1; i <= n; i++) fa[i] = i; // 指向自己return ;
}int Find_Set(int x) { // 查找空闲时间if(x <= 0) return x;else if(fa[x] == x) { // 空闲时间就是上一个flag = true; fa[x] = x - 1;return fa[x];}else return fa[x] = Find_Set(fa[x]); // 递归
}int main() {int n, ans = 0;scanf ("%d", &n);Make_Set(n);for(int i = 1; i <= n; i++) scanf ("%d %d", &a[i].t, &a[i].v);sort(a + 1, a + n + 1, cmp); for(int i = 1; i <= n; i++) {flag = false; // 找到空闲时间则为 true ,相反为 falsefa[a[i].t] = Find_Set(a[i].t); // a[i].t 的父亲结点置为之前最近的空闲时间if(flag) ans += a[i].v; // 累加答案} printf("%d", ans);return 0;
}
这篇关于家庭作业 题解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!