Week 14 模拟 A - 猫睡觉问题

题目描述

众所周知,TT家里有一只魔法喵。这只喵十分嗜睡。一睡就没有白天黑夜。喵喵一天可以睡多次!!每次想睡多久就睡多久╭(╯^╰)╮
喵睡觉的时段是连续的,即一旦喵喵开始睡觉了,就不能被打扰,不然喵会咬人哒[○・`Д´・ ○]
可以假设喵喵必须要睡眠连续不少于 A 个小时,即一旦喵喵开始睡觉了,至少连续 A 个小时内(即A*60分钟内)不能被打扰!
现在你知道喵喵很嗜睡了,它一天的时长都在吃、喝、拉、撒、睡,换句话说要么睡要么醒着滴!
众所周知,这只魔法喵很懒,和TT一样懒,它不能连续活动超过 B 个小时。
猫主子是不用工作不用写代码滴,十分舒适,所以,它是想睡就睡滴。
但是,现在猫主子有一件感兴趣的事,就是上BiliBili网站看的新番。
新番的播放时间它已经贴在床头啦(每天都用同一张时间表哦),这段时间它必须醒着!!
作为一只喵喵,它认为安排时间是很麻烦的事情,现在请你帮它安排睡觉的时间段。

这是个链接

输入

多组数据,多组数据,多组数据哦,每组数据的格式如下:
第1行输入三个整数,A 和 B 和 N (1 <= A <= 24, 1 <= B <= 24, 1 <= n <= 20)
第2到N+1行为每日的新番时间表,每行一个时间段,格式形如 hh:mm-hh:mm (闭区间),这是一种时间格式,hh:mm 的范围为 00:00 到 23:59。注意一下,时间段是保证不重叠的,但是可能出现跨夜的新番,即新番的开始时间点大于结束时间点。
保证每个时间段的开始时间点和结束时间点不一样,即不可能出现类似 08:00-08:00 这种的时间段。时长的计算由于是闭区间所以也是有点坑的,比如 12:00-13:59 的时长就是 120 分钟。
不保证输入的新番时间表有序。

输出

我们知道,时间管理是一项很难的活,所以你可能没有办法安排的那么好,使得这个时间段满足喵喵的要求,即每次睡必须时间连续且不少于 A 小时,每次醒必须时间连续且不大于 B 小时,还要能看完所有的番,所以输出的第一行是 Yes 或者 No,代表是否存在满足猫猫要求的时间管理办法。
然后,对于时间管理,你只要告诉喵喵,它什么时候睡觉即可。
即第2行输出一个整数 k,代表当天有多少个时间段要睡觉
接下来 k 行是喵喵的睡觉时间段,每行一个时间段,格式形如 hh:mm-hh:mm (闭区间),这个在前面也有定义。注意一下,如果喵喵的睡眠时段跨越当天到达了明天,比如从23点50分睡到0点40分,那就输出23:50-00:40,如果从今晚23:50睡到明天早上7:30,那就输出23:50-07:30。
输出要排序吗?(输出打乱是能过的,也就是说,题目对输出的那些时间段间的顺序是没有要求的)
哦对了,喵喵告诉你说,本题是 Special Judge,如果你的输出答案和 Sample 不太一样,也可能是对的,它有一个判题程序来判定你的答案(当然,你对你自己的答案肯定也能肉眼判断)

样例输入

12 12 1
23:00-01:00
3 4 3
07:00-08:00
11:00-11:09
19:00-19:59

样例输出

Yes
1
01:07-22:13
No

思路

综述

对于某一时间段,只有两个状态,醒着或者睡觉;
两个状态满足以下条件:
醒着:不能连续超过B小时
睡觉:必须连续大于等于A小时
将时间看做一段一段的,即醒着或者睡觉,两者交替出现,互为补集;
所有的看番的时间必须是醒着的,看番时间的补集,也即时间段的集合,可以是睡觉时间,对该集合内的时间段做判断,如果满足睡觉的要求,就睡觉,记录所有可以睡觉的时间段,即为集合sp;
求解sp的补集,即为醒着的时间段,对醒着的时间段逐一判断,若都满足醒着的条件,则猫猫可以合理安排时间,否则就不行;

过程

求两次补集,做两次判断即可解决;
Step1:
找出所有看番时间段的补集;
Step2:
对上一步找出的补集,判断能否睡觉,能睡觉的时间作为一个集合;
Step3:
对上一步做出的睡觉时间的集合求补集,即为清醒的时间;
Step4:
对上一步清醒的时间做判断;

总结

备注:代码在写的时候,时间点全部用的看番的时间点,睡觉的时间点也是用的看番的时间点,这时需要注意,因为看番的时间点不是睡觉的时间点,如果某睡觉的时间点是aa:bb–cc:dd,则前一个时间点需要加1分钟,后一个时间点需要减一分钟

我遇到的坑点

1、所有的时间点都不重合;
2、00:00的前一分钟是前一天的23:59;
3、23:59的后一分钟是后一天的00:00

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <string>
#include <climits>
#include <algorithm>
#include <queue>
#include <vector> 

using namespace std;

//思路是先找出  看番之外的时间段,然后判断是否能够睡觉,能够睡觉就加入数组sp
//然后找出睡觉之外的时间段,判断清醒是否超时


//注:闭区间处理  时间段是使用的输入的看番时间段的时间点
//所以  judge 和 right 函数里面value需要相应处理 


//结构体里面  是一个时间段 a1:b1--a2:b2 
//排序是按照起始时间排的 


struct node{
	int a1,a2,b1,b2;
	bool operator < (const node &P)const{
		if(a1 != P.a1)return a1<P.a1;
		return b1<P.b1;
	}
};


vector<node> v; 
int  A,B,N;
vector<node> v2;
vector<node> sp;//要睡觉的时间 


//找出所有的睡眠时间 
//判断该时间段是否能够  睡觉aa:bb--cc:dd     aa:bb--cc:dd 
 
void judge(node nd){
	int num = A*60;
	int value;
	if(nd.a2<nd.a1){
		value = (nd.a2+24)*60+nd.b2-nd.a1*60-nd.b1;
	}else if(nd.a2==nd.a1 && nd.b2 < nd.b1){
		value = (nd.a2+24)*60+nd.b2-nd.a1*60-nd.b1;
	}else{
		value = nd.a2*60+nd.b2-nd.a1*60-nd.b1;
	}
	value--;
	if(value>=num){
		sp.push_back(nd);
	}
}

//判断该时间段是否超过Bh 
bool right(node nd){
	int num = B*60;
	int value;
	if(nd.a2<nd.a1){
		value = (nd.a2+24)*60+nd.b2-nd.a1*60-nd.b1;
	}else if(nd.a2==nd.a1 && nd.b2 < nd.b1){
		value = (nd.a2+24)*60+nd.b2-nd.a1*60-nd.b1;
	}else{
		value = nd.a2*60+nd.b2-nd.a1*60-nd.b1;
	}
	value++;
	if(value > num){
		return false;
	}
	return true;
}

void calc(){
	v.clear();
	node nd;
	int st1,ed1;
	sort(sp.begin(),sp.end()); 
	//找到所有的清醒的时间---->存在数组v 
	st1 = sp[0].a2;ed1 = sp[0].b2;
	for(int i=1;i<sp.size();i++){
		nd.a1=st1;nd.b1=ed1;
		nd.a2=sp[i].a1;nd.b2=sp[i].b1;
		v.push_back(nd);
		st1=sp[i].a2;ed1=sp[i].b2;
	}
	nd.a1=st1;nd.b1=ed1;
	nd.a2=sp[0].a1;nd.b2=sp[0].b1;	
	v.push_back(nd);
	sort(v.begin(),v.end());
	for(int i=0;i<v.size();i++){
	    if(!right(v[i])){
	    	cout<<"No"<<endl;
	    	return; 
		}
	}
	if(sp.size()==0){
		cout<<"No"<<endl;
		return;
	}
	cout<<"Yes"<<endl;
	cout<<sp.size()<<endl;
	sort(sp.begin(),sp.end());
	for(int i=0;i<sp.size();i++){
		// 23:59      24:00     00:00
		int num1 = sp[i].a1*60+sp[i].b1;num1++;
		num1%=1440;
		int num2 = sp[i].a2*60+sp[i].b2;num2--;
		if(num2==-1){
			num2 = 23*60 + 59;
		}
		printf("%02d:%02d-%02d:%02d\n",num1/60,num1%60,num2/60,num2%60);
	}
	return;
}

void work(){
	sort(v.begin(),v.end());
//找到所有的除去看番时间之外的时间段 
	node nd;
	int st1,ed1;
	st1 = v[0].a2;ed1 = v[0].b2;
	//    0    1    2      3       4    5   
	for(int i=1;i<v.size();i++){
		nd.a1=st1;nd.b1=ed1;
		nd.a2=v[i].a1;nd.b2=v[i].b1;
		v2.push_back(nd);
		st1=v[i].a2;ed1=v[i].b2;
	}
	
	nd.a1=st1;nd.b1=ed1;
	nd.a2=v[0].a1;nd.b2=v[0].b1;
	v2.push_back(nd);
	//判断是否能够睡觉,加入sp数组 
	for(int i=0;i<v2.size();i++){
		judge(v2[i]);
	}
	
	//睡觉时间 不睡觉不行 
	if(sp.size()==0){
		cout<<"No"<<endl;
		return;
	}
	
	//计算清醒时间是否可行 
	calc();
	
} 
 
int main(){ 
	int a1,b1,a2,b2;
	while(~scanf("%d%d%d",&A,&B,&N)){
		node nd;
		
		v.clear();
		sp.clear();
		v2.clear(); 
		getchar();
		
		for(int i=0;i<N;i++){
			cin>>nd.a1;
			getchar();
			cin>>nd.b1;
			getchar();
			cin>>nd.a2;
			getchar();
			cin>>nd.b2;
			getchar();
			v.push_back(nd); 
		}
		work();
	}
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值