CCF 2017-12-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

 

 

#include<iostream>
#include<set>
#include<vector>
using namespace std;
//按时间从头到尾走会比较耗时间,容易超时
//所以采用分析每个crontab中的时间,判断是否在时间区间内部 
typedef struct Node{
	long long time;
	string work;
}Node;

bool operator<(const Node a,const Node b){//重写<  把结点装入set中 
	return a.time<b.time;
}

set<Node> time;

int getWeek(int year,int mon,int day){//根据年月日获得星期几 
	int month_day[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
	if((year%4==0 && year%100!=0) || year%400==0)month_day[2]=29;
	int sum=0;
	for(int i=1970;i<year;i++){
		if((i%4==0 && i%100!=0) || i%400==0)sum+=366;
		else sum+=365;
	}
	int m=1;
	while(m<mon){
		sum+=month_day[m];
		m++;
	}
	sum+=day;sum--;
	sum%=7;
	int res=(sum+4)%7;//星期日用数字0记录 
	return res;
}

int getNum(string s){//把数字转为字符,由于最多只有两位数,可以简单转化 
	if(s.size()==1)return s[0]-'0';
	else{
		int res=(s[0]-'0')*10+(s[1]-'0');
		return res;
	}
}

int deal(string s,vector<int> &stl){//分析输入的字符串 
	vector<string> str;
	for(int i=0;i<s.size();i++){//第一次扫描,修改大写为小写 
		if(s[i]>='A' && s[i]<='Z')s[i]+=32;
	}
	for(int i=0;i<s.size();i++){//第二次扫描,把月份星期对应的字母改为对应的数字 
		string temp=s.substr(i,3);
		string rep;
		if(temp=="jan" || temp=="mon")rep="1";
		else if(temp=="feb" || temp=="tue")rep="2";
		else if(temp=="mar" || temp=="wed")rep="3";
		else if(temp=="apr" || temp=="thu")rep="4";
		else if(temp=="may" || temp=="fri")rep="5";
		else if(temp=="jun" || temp=="sat")rep="6";
		else if(temp=="jul")rep="7";
		else if(temp=="aug")rep="8";
		else if(temp=="sep")rep="9";
		else if(temp=="oct")rep="10";
		else if(temp=="nov")rep="11";
		else if(temp=="dec")rep="12";
		else if(temp=="sun")rep="0";
		if(rep!="")s.replace(i,3,rep);//把字母替换成数字 
	}
	int i=0,j=0;
	while(j<s.size()){//第三次扫描,根据,把字符串切割 
		if(s[j]==','){
			str.push_back(s.substr(i,j-i));//把切割的片段装入数组 
			i=j+1;
		}
		j++;
	}str.push_back(s.substr(i,j-i));
	
	for(i=0;i<str.size();i++){//依次分析数组中被切割的字符串 
		string temp=str[i];
		if(temp.size()>2){//若长度大于2,则一定包含'-' 
			j=0;
			while(temp[j]!='-')j++;//先找到'-'坐标 
			int b=getNum(temp.substr(0,j));//记录'-'前一个数字 
			int e=getNum(temp.substr(j+1,temp.size()));//记录'-'后一个数字 
			for(int k=b;k<=e;k++){//从头到尾,把所有的数字,装入结果 
				stl.push_back(k);
			}
		}else{//否则只是一个数字 
			stl.push_back(getNum(temp));
		}
	}
}

int main(){
	int n;
	string s,matter;
	long long begin,end;
	cin>>n>>begin>>end;
	int begin_year=begin/100000000,end_year=end/100000000;//记录开始的年份和结束的年份 
	while(n--){
		vector<int> minu,hour,day,month,week;//记录每个类型的数据能接受的范围 
		cin>>s;  
		if(s=="*"){//输入分钟 
			for(int i=0;i<60;i++){
				minu.push_back(i);
			}
		}else deal(s,minu);
		cin>>s;
		if(s=="*"){//输入小时
			for(int i=0;i<24;i++){
				hour.push_back(i);
			}
		}else deal(s,hour);
		cin>>s;
		if(s=="*"){//输入日期
			for(int i=1;i<32;i++){
				day.push_back(i);
			}
		}else deal(s,day);
		cin>>s;   
		if(s=="*"){//输入月份 
			for(int i=1;i<13;i++){
				month.push_back(i);
			}
		}else deal(s,month);
		cin>>s;
		if(s=="*"){//输入星期
			for(int i=0;i<7;i++){
				week.push_back(i);
			}
		}else deal(s,week);
		cin>>matter;
		
		for(int i=begin_year;i<=end_year;i++){//遍历crontab包含的每个日期 
			for(int j=0;j<month.size();j++){
				int m=month[j];int mx_day=28;//mx_day记录了该月份最多的天数 
				if(m==1 || m==3 || m==5 || m==7 || m==8 || m==10 || m==12)mx_day=31;
				else if(m==4 || m==6 || m==9 || m==11)mx_day=30;
				else if(((i%4==0 && i%100!=0) || i%400==0) && m==2)mx_day=29;
				for(int k=0;k<day.size();k++){
					int d=day[k];
					if(d<=mx_day){//只要数组中包含的日期不超过该月份最多的天数,就可以判断 
						int w=getWeek(i,m,d);//获得遍历到的日期的星期数 
						for(int l=0;l<week.size();l++){//再去找星期数组 
							if(w==week[l]){//若找到了,则该日期满足要求,计入crontab总时间表 
							//注意int类型的i乘以100000000会爆掉,一定要强制类型转换为long long 
								long long t=(long long)i*100000000+m*1000000+d*10000;
								for(int o=0;o<hour.size();o++){
									int th=hour[o]*100;
									for(int p=0;p<minu.size();p++){
										int tm=minu[p];
										Node temp;
										temp.time=t+th+tm;
										temp.work=matter;
										time.insert(temp);
									}
								}
							}
						}
					}
				}
			}
		}
		
	}
	
	for(set<Node>::iterator it=time.begin();it!=time.end();it++){
		Node temp=(*it);
		if(temp.time>=begin && temp.time<end){
			cout<<temp.time<<" "<<temp.work<<endl;
		}
	}
} 

更多相关CCF的试题解答,请点击>>CCF历年认证考试解答

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值