CCF201712-3 Crontab(100分)

试题编号:201712-3
试题名称:Crontab
时间限制:10.0s
内存限制:256.0MB
问题描述:



样例输入

3 201711170032 201711222352
0 7 * * 1,3-5 get_up
30 23 * * Sat,Sun go_to_bed
15 12,18 * * * have_dinner

样例输出

201711170700 get_up
201711171215 have_dinner
201711171815 have_dinner
201711181215 have_dinner
201711181815 have_dinner
201711182330 go_to_bed
201711191215 have_dinner
201711191815 have_dinner
201711192330 go_to_bed
201711200700 get_up
201711201215 have_dinner
201711201815 have_dinner
201711211215 have_dinner
201711211815 have_dinner
201711220700 get_up
201711221215 have_dinner
201711221815 have_dinner

问题连接:CCF201712-3 Crontab

解题思路:直接模拟,具体看程序注释。

提交后得100分的C++程序:

#include<iostream>
#include<string>
#include<utility>
#include<cstring>
#include<vector>
#include<queue>
 
using namespace std;
 
int days[]={0,31,28,31,30,31,30,31,31,30,31,30,31};

//月份表和星期表 
string m[13]={"","jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec"};
string w[7]={"sun","mon","tue","wed","thu","fri","sat"}; 

//字符串转整数 
int myatoi(string s)
{
	int res=0;
	for(int i=0;i<s.length();i++)
	  res=res*10+s[i]-'0';
	return res;
}

 
bool isleap(int y)
{
	return ((y%400==0)||(y%4==0&&y%100!=0));
}
 
//计算距离1970 1 1 星期四 的天数,输入1970 1 1 输出0 
int sum(int y,int m,int d)
{
	int sum=0;
	for(int i=1970;i<y;i++){
		sum+=365;
		if(isleap(i))
		  sum++;
	}
	for(int i=1;i<m;i++)
	  sum+=days[i];
	sum+=d;
	if(m>2&&isleap(y))
	  sum++;
	sum--;//保证输入1970 1 1输出0 
	return sum;
}

//月份、星期映射 
int mymap(int op,string s)
{
	if(op==3)//返回月份的映射
	{
		for(int i=1;i<13;i++)
	      if(m[i]==s)
	        return i; 
	}
	else if(op==4)//返回星期的映射
	{
		for(int i=0;i<7;i++)
	      if(w[i]==s)
	        return i;
	}
	return -1;
}
 
struct Time{
	int y,m,d,h,min;
	Time(string s){//yyyymmddHHMM格式 
		string str;
		str=s.substr(0,4),y=myatoi(str);
		str=s.substr(4,2),m=myatoi(str);
		str=s.substr(6,2),d=myatoi(str);
		str=s.substr(8,2),h=myatoi(str);
		str=s.substr(10,2),min=myatoi(str);
	}
};
 
void read(vector<pair<int,int> > &p,char *a,int op)
{
	vector<string>tmp;
	string s1,s2;
	//用 ","进行分割,结果保存在tmp中
	char *sp=strtok(a,",");
	while(sp){
		tmp.push_back(sp);
		sp=strtok(NULL,",");
	} 
	//用 "-"进行分割
	for(int i=0;i<tmp.size();i++){
		int pos=tmp[i].find("-");
		if(pos==string::npos)//只有一个数 
			s1=s2=tmp[i];
		else{
			s1=tmp[i].substr(0,pos);
			s2=tmp[i].substr(pos+1);
		}
		int v1=-1,v2=-1;
		//如果是月份或者星期还要进行映射
		if(op==3||op==4)
		{
			v1=mymap(op,s1);
		    v2=mymap(op,s2);
		}
		if(v1==-1) v1=myatoi(s1);
		if(v2==-1) v2=myatoi(s2);
		p.push_back(make_pair(v1,v2));
	}
}
 
bool judge(int m,vector<pair<int,int> > &v)
{
	for(int i=0;i<v.size();i++)
	  if(v[i].first==-1||(v[i].first<=m&&m<=v[i].second))
	    return true;
	return false;
}

//判断当前时间是否大于等于结束时间,没有就返回true 
bool end_time(int y,int m,int d,int h,int min,const Time &e)
{
	if(y<e.y) return true;
	if(m>e.m) return false;
	if(m<e.m) return true;
	if(d>e.d) return false;
	if(d<e.d) return true;
	if(h>e.h) return false;
	if(h<e.h) return true;
	if(min>e.min) return false;
	if(min<e.min) return true;
	return false;
} 

struct Result{
	int id;
	long long time;
	string task;
	Result(){}
	Result(int id,long long time,string task):id(id),time(time),task(task){}
	//按时间和先后顺序排好序 
	bool operator<(const Result &a)const
	{
		return (time==a.time)?(id>a.id):(time>a.time);
	}
};

vector<pair<int,int> >v[5];//0-5分别表示 min,h,d,m,w的范围,如果是 * 则用<-1,-1>表示 



int main()
{
	int n;
	string s,t;
	//读入数据 
	cin>>n>>s>>t;
	Time st(s),et(t);
	priority_queue<Result>q;//结果队列 
	for(int i=0;i<n;i++){
		  char a[100];
		  for(int j=0;j<5;j++){		
		    v[j].clear(); 
		    scanf("%s",a);
		    strlwr(a);//转换成小写
		    if(strcmp(a,"*")==0)
		     v[j].push_back(make_pair(-1,-1)); 
		    else
		      read(v[j],a,j); //j= 3 4 是输入月份和星期要进行映射 
		}
		cin>>s;//任务名
		int m=st.m,d=st.d,h=st.h,min=st.min; 
		for(int y=st.y;y<=et.y;y++,m=1)
		  for(;m<=12;m++,d=1)
		    if(judge(m,v[3]))//满足月份
		    {
		  	  int up=days[m];
		  	  if(m==2&&isleap(y))
		  	    up++;
		  	  for(;d<=up;d++,h=0)
		  	    if(judge(d,v[2])&&judge((sum(y,m,d)+4)%7,v[4]))//满足号数和星期数 
				{
					for(;h<24;h++,min=0)
					  if(judge(h,v[1]))//满足小时数 
					  {
					  	 for(;min<60;min++)
					  	 {
						     if(!end_time(y,m,d,h,min,et))//结束 
						       break;
					         if(judge(min,v[0]))//满足分钟数
						     {
							  	long long time=(long long)y*100000000+(long long)m*1000000+(long long)d*10000+(long long)h*100+min;
							  	q.push(Result(i,time,s));
						     } 
					     }
				    }
		       }
			}		
		}
	while(!q.empty())
	{
		Result f=q.top();
		cout<<f.time<<" "<<f.task<<endl; 
		q.pop();
	}
	return 0;	  
}

 

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值