week14——实验(模拟题 CHAOS LV15)

猫睡觉问题:

问题描述

题目简述

众所周知,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

问题分析

解题思路

这个题的思路其实非常的简单,就是:能睡的时候就多睡会,睡醒了起来看番,看完了能睡就接着睡。实际上就是按照番剧的开始时间从小到大排序,之后算出番剧之间的时间间隔(排序第一的番剧要与最后的番剧算)。然后在相邻番剧间隔大于最低睡觉时长的时间段安排睡觉,其他时间安排看番或者醒着。同时使用一个变量维护连续醒着的时长,当发现时长超过最大时长时,失败,否则成功。总体来说思路还是比较简单的。但是,难点在于番剧之间的间隔的算法,尤其是第一个番剧和最后一个番剧的时间间隔很麻烦。但是经过简化后,可以发现,番剧之间的间隔分为两类,一类是跨过0点的两番剧间隔,此时需要独立运算,其间隔为两番剧到0点的和,其他的直接运算就可以,即后项的开始时间减去前项的结束时间。如果算出的时间间隔为负数,则使得该数加1440即可(这里画个圆就很容易知道,这个负数是节目长度的绝对值)。最后是开始的位置,这里选择第一个间隔大于最低睡眠时间的番剧开始时间,这样可以保证在看该番剧的时候猫咪一定是刚起的,即连续清醒时间为0。最后按照格式输出即可。

参考代码
#include <iostream>
#include <string>
#include <algorithm>
#include <cstring>

using namespace std;

class times
{
public:
	int s[2];
	int e[2];
	int kuaye;
	void ini(string init)
	{
		s[0]=(init[0]-48)*10+(init[1]-48);
		s[1]=(init[3]-48)*10+(init[4]-48);
		e[0]=(init[6]-48)*10+(init[7]-48);
		e[1]=(init[9]-48)*10+(init[10]-48);
		if(s[0]>e[0]) kuaye=1;
		else kuaye=0;
	}
	bool operator <(const times& t) const
	{
		if(s[0]!=t.s[0]) return s[0]<t.s[0];
		else return s[1]<t.s[1];
	}
	bool operator ==(const times& t) const
	{
		return (s[0]==t.s[0]&&s[1]==t.s[1]&&e[0]==t.e[0]&&e[1]==t.e[1]);
	}
	int operator -(const times& t) const
	{
		if(t<*this||t==*this||t.kuaye==1)
		{
			int a;
			if(s[1]>=t.e[1])
			{
				a=((s[0]-t.e[0])*60+(s[1]-t.e[1])-1);
			}
			else a=((s[0]-1-t.e[0])*60+(s[1]+60-t.e[1])-1);
			if(a<0) a+=1440;
			return a;
		}
		else
		{
			return ((23-t.e[0])*60+(60-t.e[1])+(s[0])*60+s[1]-1);
		}
	}
	int change()
	{
		if(kuaye==0)
		{
			if(e[1]<s[1])
			{
				return ((e[0]-1-s[0])*60+(e[1]+60-s[1]+1));
			}
			else 
			{
				return ((e[0]-s[0])*60+(e[1]-s[1]+1));
			}
		}
		else 
		{
			return ((23-s[0])*60+(60-s[1])+(e[0])*60+(e[1]+1));
		}
	}
	void print()
	{
		int a,b,c,d;
		a=s[0];
		b=s[1];
		c=e[0];
		d=e[1];
		if(a<10) printf("0%d",a);
		else printf("%d",a);
		if(b<10) printf(":0%d-",b);
		else printf(":%d-",b);
		if(c<10) printf("0%d",c);
		else printf("%d",c);
		if(d<10) printf(":0%d",d);
		else printf(":%d",d);
	}
};

int dt[25];

int main()
{
	int a,b,k;
	while(scanf("%d %d %d",&a,&b,&k)!=EOF)
	{
		memset(dt,0,sizeof(dt));
		bool can=true;
		int count=0;
		int temp=0;
		int start=-1;
		string str;
	    times* table;
	    times* ans;
	    table=new times[k];
	    ans=new times[k];
	    for(int i=0;i<k;i++)
	    {
		    cin>>str;
		    table[i].ini(str);
	    }
	    a=a*60;
	    b=b*60;
	    sort(table,table+k);
	    for(int i=0;i<k;i++)
		{
			int a=i;
			int b=i-1;
			if(b<0) b=k-1;
			dt[i]=table[a]-table[b];
		}
		for(int i=0;i<k;i++)
		{
			if(dt[i]>=a)
			{
				start=i;
				break;
			}
		} 
		if(start==-1) 
		{
			printf("No\n");
	        continue;
		}
		for(int i=0;i<k;i++)
		{
			temp+=table[(start+i)%k].change();
			if(dt[(start+i+1)%k]<a)
			{
				temp+=dt[(start+i+1)%k];
			}
			if(temp>b) 
			{
				can=false;
				break;
			}
			if(dt[(start+i+1)%k]>=a)
			{
				temp=0;
				int a,b,c,d;
				a=table[(start+i)%k].e[0];
				b=table[(start+i)%k].e[1]+1;
				c=table[(start+i+1)%k].s[0];
				d=table[(start+i+1)%k].s[1]-1;
				if(b==60)
				{
				    b=0;
					a=a+1;
					if(a==24) a=0;	
				}
				if(d==-1)
				{
					d=59;
					c=c-1;
					if(c==-1) c=23;
				}
				ans[count].s[0]=a;
				ans[count].s[1]=b;
				ans[count].e[0]=c;
				ans[count].e[1]=d;
				count++;
			}
		}
		if(can)
		{
			printf("Yes\n");
			printf("%d\n",count); 
			for(int i=0;i<count;i++)
			{
				ans[i].print();
				printf("\n");
			}
		}
		else printf("No\n");
	}
	return 0;
} 

心得体会

非常难的一道题,需要考虑的细节有些多,虽然思路上来说并不困难。这里尤其是要注意能否考虑到疲劳累积的问题,即需要选择一个猫咪必然的刚醒的点为起始,否则,不能保证轮询一圈下来之后最终状态和初始状态相同。另外就是,第一个番剧和最后的番剧的处理真的很难,需要考虑很久才可以找到规律。总之,挺难的一道题目,做出来真的非常有成就感,虽然时间过长了。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值