#10008. 「一本通 1.1 练习 4」家庭作业
【题目描述】
老师在开学第一天就把所有作业都布置了,每个作业如果在规定的时间内交上来的话才有学分。每个作业的截止日期和学分可能是不同的。例如如果一个作业学分为 10,要求在 6 天内交,那么要想拿到这 10 学分,就必须在第 6 天结束前交。
每个作业的完成时间都是只有一天。例如,假设有 7 次作业的学分和完成时间如下:
作业号 | 期限 | 学分 |
---|---|---|
11 | 11 | 66 |
22 | 11 | 77 |
33 | 33 | 22 |
44 | 33 | 11 |
55 | 22 | 44 |
66 | 22 | 55 |
77 | 66 | 11 |
最多可以获得 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
【数据范围与提示】
对于 20\%20% 的数据,N≤10^3;
对于 40\%40% 的数据,N≤10^4;
对于 60\%60% 的数据,N N≤10^5;
对于 100\%100% 的数据,N≤10^6,作业的完成期限均小于 7×10^5。
思路:看完代码和我的解析之后你会发现特别像loj之前做过的一道贪心题智力大冲浪简直就是一模一样的思路,其实就是一样的。定义一个bool数组v判断有没有获得当前期限的学分,没有获得过就可以获得,然后再定义一个bk=false,判断到最后到底可不可以获得学分,还定义了一个东西就是省略时间的优化的一个界限(这个是和智力大冲浪唯一的区别难点)
【智力大冲浪的代码】
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int read()//日常快读
{char c=getchar();int x=0,f=1;while(c<48 || c>57){if(c=='-') f=-1;c=getchar();}while(c>=48 && c<=57){x=x*10+c-48;c=getchar();}return x*f;
}
struct node
{int t,w;//t表示时间期限 //w表示罚款
}a[110000];
bool cmp(node n1,node n2)
{return n1.w>n2.w;//按罚款额从大到小排序
}
bool bk=false;//这个是判断要不要罚款,一开始初始化全部都要罚款
bool v[110000];//这个是用来判断当前这个时间期限的所有期限要不要罚款
int main()
{memset(v,true,sizeof(v));//初始化全部都不用罚款 int m,n; m=read(); n=read();for(int i=1;i<=n;i++) a[i].t=read();for(int i=1;i<=n;i++) a[i].w=read();sort(a+1,a+n+1,cmp);//按罚款额的大小进行排序 for(int i=1;i<=n;i++){bk=false;//最开始要罚款 for(int j=a[i].t;j>=1;j--)/*这个是按时间期限来枚举判断因为我们要按时间的完成度来罚款所以自然就是以时间来罚款的啦还有一个就是如果我要知道这一种情况到底是不是不可以的那我就一定要把这个时间的每一个时间点都给计算一遍如果每一次都不可以的话,说明这个任务就是不能完成的 */ {if(v[j]==true)/*如果这一步进入不了的话那就继续上面的j的循环,而不是退出到i的循环这样循环是为了对当前的这一个游戏公平说当前的游戏不能做的话,一定是因为他的所有期限都完成不了,才可以罚款所以当前的这一个不行不代表前面的不行比如说:期限为4的话,4我们记录过不行,但是3,2,1我们没有记录那就不能说我们当前的这种情况要完成不了,就不能说当前的这一个游戏我们要罚款 */ {v[j]=false;/*就把当前这种方案变为false,表示记录过下一次在出现的话就要判断为false,也就是不能用 */ bk=true;//然后bk=true,说明不用罚款 break;//退出循环,到下面判断到底需不需要罚款 }}if(bk==false) m-=a[i].w;/*注意这一步不是最后判断的,而是在上面的break之后就立刻判断,如果经过了上面那一步不成立的话就说明当前的这一种方式不可以走,所以就要罚款 */ }printf("%d\n",m);//剩下的钱就是可以拿到的最多的钱 return 0;
}
/*
样例输入
10000
7
4 2 4 3 1 4 6
70 60 50 40 30 20 10
样例输出
9950
样例解释:第5个游戏和第6个游戏不能完成
到第五个游戏的时候,1到4这四个期限在v数组里面都已经是false
所以第五个的1就直接false了,就要罚款30元
然后到第六个游戏的时候,1到4这四个期限还是不行的
所以就直接false掉了,就要罚款20元
第七个游戏就可以,因为期限为6在前面没有出现过
所以就是10000-30-20=9950
*/
【家庭作业的代码一:好理解一点的】
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int read()//日常快读,时间减少400多ms
{char c=getchar();int x=0,f=1;while(c<48 || c>57){if(c=='-') f=-1;c=getchar();}while(c>=48 && c<=57){x=x*10+c-48;c=getchar();}return x*f;
}
struct node//定义结构体
{int x,y;//x表示作业的完成期限 //y表示作业的学分
}a[1100000];
bool v[710000];//v是判断当前期限的学分是否获取过
bool cmp(node n1,node n2)
{return n1.y>n2.y;//因为要获得最大的学分,所以是按照学分从大到小来排序
}
int main()
{memset(v,false,sizeof(v));int n; n=read();for(int i=1;i<=n;i++){a[i].x=read();a[i].y=read();}sort(a+1,a+n+1,cmp);//结构体的目的在此,一连套排序 int ans=0,dislike=0;//ans是用来记录最大的学分 /*dislike是用来记录当前不能够再次完成的期限(用dislike是好理解,就是当前遇到dislike这个期限的话这个期限对应的学分是拿不到的)举个例子:2 5 和 2 4 和 2 3 我先在期限为2,学分为5的作业上面完成了那么这个时候期限为2的我们已经用过的所以在 2 4 的时候,dislike在v数组等于false之后就会更新为当前不能再次完成的期限2然后到 2 3 的时候,就会直接跳过因为再进行判断也无法获得学分还有一个要注意的就是我们的当前到达的这个dislike的前面比他小的期限都是无法完成的因为dislike是完全不能完成,所以因为完全不能完成就必须是从1-dislike都不能完成那么dislike前面的完成期限都是不能完成的所以可以说是一个优化当然不加这个dislike也是可以的,只不过时间会超限因为如果一大堆数都是同一个完成期限的话每一次都要判断,时间自然就会长所以为了ac,这个dislike是一定要加的 */ for(int i=1;i<=n;i++) {if(a[i].x<=dislike) continue;/*这个就是我上面说的情况,如果期限小于或者等于dislike就自动忽略,循环下一个i */ bool bk=false;/*bk是用来判断当前可不可以获得学分如果不可以,就要更新dislike */ for(int j=a[i].x;j>=1;j--)/*从他的最大期限开始循环是因为我们为了不漏掉比如说期限为2的我们pass掉的但是当前的这一个作业期限为6如果我们从1开始的话就会pass掉这一个就会浪费掉学分因为期限为6的这一个是可以获得学分的 */{if(v[j]==false)/*如果v[j]==false说明当前这个期限还没有获取过学分就意味者当前这个期限可以获取学分 */ {v[j]=true;//更新为获取过 ans+=a[i].y;//增加学分 bk=true;//bk判断为可以获取 break;//退出循环,到下一步的判断包括bk }}if(bk==false) dislike=a[i].x;/*如果bk==false,说明这一个作业不能获得学分就要更新当前的dislike的作业期限 */ }printf("%d\n",ans);return 0;
}
【家庭作业代码二:高级一点的】
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int mymax(int x,int y){return x>y?x:y;}//这个是max的更快版
inline int read()//日常快读,时间减少400多ms
{char c=getchar();int x=0,f=1;while(c<48 || c>57){if(c=='-') f=-1;c=getchar();}while(c>=48 && c<=57){x=x*10+c-48;c=getchar();}return x*f;
}
struct node//结构体排序
{int x,y;
}a[1110000];
int cmp(node n1,node n2)
{return n1.y>n2.y;
}
int fa[710000];
int find(int x)//这个如果我没记错的话是并查集里面用到的找父亲
/*这个找父亲在这里的作用就是判断当前的学分能不能获取其实和我之前打的那个代码是一样的就是一个一个循环,递减然后再判断是不是每一步都失败
*/
{if(fa[x]==x) return x;/*如果当前的fa数组的期限与当前的期限一样就把x返回给fx,说明当前这个a[i].x的这个期限是可以用的就可以增加学分 */ else return fa[x]=find(fa[x]);/*否则的话,就返回fa[x],其实是减了1之后的值说实在的这个函数解析起来不容易大家还是调试吧,之前的那个代码理解起来会容易一些 */
}
int main()
{int n; n=read(); int ans=0;int maxx=0;for(int i=1;i<=n;i++){a[i].x=read();a[i].y=read();maxx=max(maxx,a[i].x);//maxx记录最大期限 }for(int i=1;i<=maxx;i++) fa[i]=i;//最开始的fa数组与完成期限同步 sort(a+1,a+n+1,cmp);//排序 for(int i=1;i<=n;i++){int fx=find(a[i].x);//fx记录返回回来的值 if(fx!=0)//如果不等于0,说明当前这个期限还有可以完成的余地 {ans+=a[i].y;//就增加学分 fa[fx]=fx-1;//然后这一步其实就是之前的j-- }}printf("%d\n",ans);return 0;
}
大概就是这样,真的是和智力大冲浪一模一样的思路。
#10008. 「一本通 1.1 练习 4」家庭作业相关推荐
- LOJ #10008. 「一本通 1.1 练习 4」家庭作业
智力大冲浪的数据加强版,n^2算法要被卡. 我们发现,原来的暴力代码最暴力的是这一段: for (register int j=num[i].pos; j>=1; --j) if (!f[j]) ...
- 「一本通 6.5 练习 3」迷路
「一本通 6.5 练习 3」迷路 题目描述 大意说一个给你有向图, 一个有n个节点,每个节点相连的边为所需要花费的时间, 问你从1到n 在时间刚好为t是的方案数.输出%2009 注意:不能在某个节点逗 ...
- 【C++】「一本通 1.1 例 4」加工生产调度
「一本通 1.1 例 4」加工生产调度 [来源] [题目描述] [输入格式] [输出格式] [输入样例] [输出样例] [数据范围] [解析] [代码] [来源] 一本通题库-1425 LibreOJ ...
- LibreOJ10082. 「一本通 3.3 例 1」Word Rings【二分+SPFA】
10082. 「一本通 3.3 例 1」Word Rings [题目描述] 传送门 [题解] 将一个字符串看成一条边,字符两端的字符看成节点,长度看成权值.二分枚举答案,最后SPFA刷正环,因为只要有 ...
- #10016. 「一本通 1.2 练习 3」灯泡(三分)
参考博客链接:「一本通 1.2 练习 3」灯泡(三分) #include<stdio.h> #include<string.h> #include<math.h> ...
- 【C++】「一本通 1.1 例 2」种树
「一本通 1.1 例 2」种树 [来源] [题目描述] [输入格式] [输出格式] [输入样例] [输出样例] [解析] [代码] [来源] 一本通题库-1423 LibreOJ-10001 vjud ...
- #10001. 「一本通 1.1 例 2」种树
#10001. 「一本通 1.1 例 2」种树 满足n个区间种树的要求,求最少种多少棵数 思路 按照区间的尾巴来排序,因为如果区间有重叠的种在第一个区间的尾巴可以使得种树更少,所有每次始从尾巴开始种树 ...
- 【C++】「一本通 1.1 例 5」智力大冲浪
「一本通 1.1 例 5」智力大冲浪 [来源] [题目描述] [输入格式] [输出格式] [输入样例] [输出样例] [数据范围] [解析] [代码] [来源] 一本通题库-1426 LibreOJ- ...
- 「一本通 1.2 例 2」Best Cow Fences
题目链接: 链接: [link](信息学奥赛一本通(C++版)在线评测系统). 首先这道题要求找平均数,且要求所选片段长度需要大于等于l.那么首先想到的就是最暴力的方法就是找到所有大于等于l的片段在其 ...
最新文章
- 阿里P9:架构师最根本的差距是思维!
- JSR315(JavaTM Servlet 3.0 Specification)
- mysqldump工具,工作的本质是什么呢?(dump表的时候,是否会产生drop表的语句)
- 全球及中国汽车涂料市场前景态势与投资渠道分析报告2022版
- 接口继承中一个常见问题的思考
- 记录某一天安服仔的漏洞挖掘过程
- 多重线性回归 多元线性回归_了解多元线性回归
- mysql配置文件结构_MariaDB/MySQL配置文件my.cnf解读
- 工作流实战_26_flowable 变量判断汇总
- 黑马h5学习代码_如何零基础制作酷炫实用的H5页面
- Corba传值包含中文解决
- 花书+吴恩达深度学习(三)反向传播算法 Back Propagation
- Xcode常用的快捷键有哪些?
- 问卷小程序php,问卷调查小程序(tp后台)
- 12306验证码的一些思考
- Report WebCore crash to the ErrorReportUtils at:Fri Jul 24 09:59:08 格林尼治标准时间+0800 2015
- 回顾过去。。展望未来
- 《迅雷链精品课》第六课:主流区块链数据存储分析(一)
- C++ 汇编代码分析——递归函数调用、浮点数比较、选择语句
- Docker 生产环境之安全性 - 适用于 Docker 的 AppArmor 安全配置文件