试题编号: | 201712-3 |
试题名称: | Crontab |
时间限制: | 10.0s |
内存限制: | 256.0MB |
问题描述: | 样例输入 3 201711170032 201711222352 样例输出 201711170700 get_up |
#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历年认证考试解答