SDU程序设计思维与实践Week14 猫睡觉问题

猫睡觉问题

猫睡觉的时段是连续的,即一旦开始睡觉了,就不能被打扰。猫必须要睡眠连续不少于 A 个小时,即一旦猫开始睡觉了,连续至少 A 个小时内(即A*60分钟内)不能被打扰。猫需要在一段时间内醒着,但不能连续醒着超过 B 个小时。每天需要醒着的时间都是一样的。求猫睡觉的时间段。

输入

多组数据,多组数据,多组数据哦,每组数据的格式如下:
第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。注意一下,时间段是保证不重叠的,但是可能出现跨夜,即开始时间点大于结束时间点。12:00-13:59 的时长是 120 分钟。
保证每个时间段的开始时间点和结束时间点不一样,即不可能出现类似 08:00-08:00 这种的时间段。

输出

输出的第一行是 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。

输入样例

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

思路分析

  • 判断单一的一个醒着的时间的长度是否超过Bh。
  • 对需要醒着的时间段按照起始时间进行排序
  • last表示上一个醒着的时间区间。
  • 从前向后遍历需要醒着的区间,判断区间的开始到上一区间的结束的这段时间能否睡觉。
  • 如果能睡觉,更新last的开始和结束,并且将睡觉的时间加入答案。
  • 如果不能睡觉,更新last的结束,并判断last的长度是否超过了B小时。
  • 最后一个需要醒着的时段的结束时间和第一个需要醒着的时段的开始时间的间隔如果超过了Ah,让猫睡觉。
  • 否则,判断醒着的时间是否超时。

解题代码

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
int A,B,N,day=24*60;
bool flag;
struct timeinterval{
	int startime,endtime;
	bool operator <(const timeinterval& t){
		return startime<t.startime;
	} 
} ;
vector<timeinterval> v;
timeinterval time[25],tempt,last;
string temp;
int toMin(string s){
	int ret=0;
	ret=(s[0]-'0')*10*60+(s[1]-'0')*60+(s[3]-'0')*10+(s[4]-'0');
	return ret;
}
string tostring(int x){
	string ret="07:00";
	ret[0]=x/600+'0';x%=600;
	ret[1]=x/60+'0';x%=60;
	ret[3]=x/10+'0';x%=10;
	ret[4]=x+'0';
	return ret;
}
int main(){
	while(cin>>A>>B>>N){
		A*=60,B*=60;flag=true;
		for(int i=0;i<N;i++){
			cin>>temp;
			time[i].startime=toMin(temp);
			time[i].endtime=toMin(temp.substr(6));
			if(time[i].startime>time[i].endtime) time[i].endtime+=day;
			if(time[i].endtime-time[i].startime+1>B){
				flag=false;
			}
		}
		if(!flag){
			cout<<"No"<<endl;continue;
		}
		sort(time,time+N);
		v.clear();		
		last.startime=time[0].startime,last.endtime=time[0].endtime;
		for(int i=1;i<N;i++){
			if(time[i].startime-last.endtime-1>=A){//睡 
				tempt.startime=last.endtime+1;
				tempt.endtime=time[i].startime-1;
				if(tempt.startime!=tempt.endtime) v.push_back(tempt);
				last.startime=time[i].startime;
				last.endtime=time[i].endtime;
			}
			else{//不睡
				last.endtime=time[i].endtime;
				if(last.endtime-last.startime+1>B){
					flag=false;break;
				} 			
			}
		}
		if(!flag){
			cout<<"No"<<endl;continue;
		} 
		if(time[0].startime+day-last.endtime-1>=A){
			tempt.startime=(last.endtime+1)%day;
			tempt.endtime=(time[0].startime+day-1)%(day);
			if(tempt.startime!=tempt.endtime) v.push_back(tempt);
		}
		else if(v.size()==0||(v[0].startime-1+day)%day-last.startime+1>B){
			cout<<"No"<<endl;continue;
		}
		cout<<"Yes"<<endl;
		cout<<v.size()<<endl;
		for(int i=0;i<v.size();i++){
			cout<<tostring(v[i].startime)<<"-"<<tostring(v[i].endtime)<<endl;
		} 
	}
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值