Week14 限时模拟 - 猫睡觉问题 [HDU - 3700]

原题链接

http://acm.hdu.edu.cn/showproblem.php?pid=3700

题目描述

在这里插入图片描述

题目里的坑

1. 时间段全部是闭区间,这意味着睡觉时间的端点和看番时间的端点不能重合,计算时间长度也不能简单的用两个端点相减。
2. 别看样例里边给的时间段都是有序的,题目里没说有序,所以需要排序。
3. 题目中的A和B分别是指连续睡觉或醒着的时间要求,而不是对睡觉或醒着的总时间的要求。
4. 猫不能一直不睡觉(如果一个睡觉时间段也没有,必须输出No)。
5. Yes和No,不是YES和NO。
6. 时间不要出现-1和1440,这两个最后分别要输出23:59和00:00。

基本思路

为了更好的处理时间,需要将所有的时间字符串转化成时间点(int类型, h o u r × 60 + m i n hour \times 60+min hour×60+min)处理。

这个题的难点在于处理那些跨夜的时间段(开始时间点大于结束时间点)。

题目输入给的是一天内的番剧的时间表(最后一部番的结束时间 - 第一部番的开始时间不会超过24h)。我们可以把时间想象成一个环,绕环一周是24h。只要我们从一部番的开始时间 t 0 t0 t0 统计,一直统计 t 0 + 24 × 60 m i n t0+24\times 60min t0+24×60min 即可。
可以定义一个时间点结构体TimePoint,其中包含时间点t,以及时间点状态st(表示是番的开始时间还是结束时间)。

维护一个TimePoint类型的结构体数组tp,里面包含所有 t 0 t0 t0 t 0 + 24 × 60 m i n t0+24 \times 60min t0+24×60min的所有番剧的起始时间点和结束时间点(从小到大有序排列)。 t 0 t0 t0可以选取输入时间表中最早播出的番剧的起始时间。如果一部番剧的结束时间小于起始时间,那么结束时间要加上 24 × 60 24\times60 24×60以区分,最后将 t 0 + 24 × 60 t0+24 \times 60 t0+24×60加入tp数组

假设tp数组中有n+1个时间点,那么这些时间点形成了n个时间段,其中,有些是番剧播出时间段,有些是空闲的时间段。

遍历前n个时间点(也就是遍历前n个时间段,第i个时间段有tp[i]和tp[i+1]组成),并记录可以用来睡觉的时间段,维护连续醒着的时间,从而判断是否存在满足要求的时间安排。

完整代码

#include<iostream>
#include<sstream>
#include<string> 
#include<vector>
#include<algorithm>
#include<cstdlib> 
using namespace std;
#define T 1440
int transto(const string &ts)
{
	int t1, t2;
	char tmp;
	istringstream iss(ts);
	iss>>t1>>tmp>>t2;
	return t1*60+t2;
}
string transback(int t)
{
	string ts;
	stringstream ss;
	int t1 = t/60;
	int t2 = t%60;
	if(t1 < 10)	ss<<0;	ss<<t1;
	ss<<":";
	if(t2 < 10)	ss<<0;	ss<<t2;
	ss>>ts;
	return ts;
}
struct TimePoint{
	int t;
	string st;
	TimePoint(int t, const string &st)
	{
		this->t = t;
		this->st = st;
	}
	bool operator <(const TimePoint &tp) const
	{
		return t < tp.t;
	}
};
vector<TimePoint> tp;
vector<string> slpt;
int A, B, N;
int n, dt, b, st, ed, mint; //b:连续活动时间 
string tmp;
bool flag;
int main ()
{
	while(cin>>A>>B>>N)
	{
		A *= 60;
		B *= 60;
		getchar();
		tp.clear();
		slpt.clear();
		flag = true;
		mint=2*T;
		for(int i=0;i<N;i++)
		{
			getline(cin, tmp, '-');
			st = transto(tmp);
			getline(cin, tmp, '\n');
			ed = transto(tmp);
			if(st > ed)	ed += T;
			if(st < mint)	mint=st;
			tp.push_back({st, "s"});
			tp.push_back({ed, "e"});
		}
		sort(tp.begin(), tp.end());
		tp.push_back({mint+T, "s"});
		n=tp.size()-1;
		b = 0;
		int first = 0;
		for(int i=0;i<n;i++)
		{
			dt = tp[i+1].t - tp[i].t;
			if(tp[i].st == "s")
			{
				
				b += dt+1;
				if(b > B)
				{
					flag = false;
					break;
				}
			}
			else
			{
				if(dt-1 >= A)
				{
					slpt.push_back(transback((tp[i].t+1) % T) + "-" + transback((tp[i+1].t-1) % T));
					if(!first)	first = b;
					b = 0;
				}
				else
				{
					b += dt-1; 
					if(b > B)
					{
						flag = false;
						break;
					}
					if(i == n-1 && b+first>B)
					{
						flag=false;
						break;
					}
				}
			}
		}
		if(slpt.empty())	flag=false;
		if(flag)
		{
			cout<<"Yes"<<endl;
			cout<<slpt.size()<<endl;
			for(int i=0, l=slpt.size();i<l;i++)	cout<<slpt[i]<<endl;
		}
		else
		{
			cout<<"No"<<endl;
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值