试题编号: | 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历年认证考试解答