zoukankan      html  css  js  c++  java
  • 家庭作业 题解

    小编:真是一道有趣的题,通过量还不算低,我也就写写自己的想法

    题目描述

    老师在开学第一天就把所有作业都布置了,每个作业如果在规定的时间内交上来的话才有学分。每个作业的截止日期和学分可能是不同的。例如如果一个作业学分为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 ,相反为 false
    		fa[a[i].t] = Find_Set(a[i].t); // a[i].t 的父亲结点置为之前最近的空闲时间
    		if(flag) ans += a[i].v; // 累加答案
    	} 
    	printf("%d", ans);
    	return 0;
    }
    
  • 相关阅读:
    Java学习笔记三十:Java小项目之租车系统
    Java学习笔记二十九:一个Java面向对象的小练习
    Java学习笔记二十八:Java中的接口
    Java学习笔记二十七:Java中的抽象类
    Java学习笔记二十六:Java多态中的引用类型转换
    Java学习笔记二十五:Java面向对象的三大特性之多态
    Java学习笔记二十四:Java中的Object类
    Java学习笔记二十三:Java的继承初始化顺序
    Java学习笔记二十二:Java的方法重写
    Java学习笔记二十一:Java面向对象的三大特性之继承
  • 原文地址:https://www.cnblogs.com/Chain-Forward-Star/p/13868049.html
Copyright © 2011-2022 走看看