试题编号: | 201712-3 |
试题名称: | Crontab |
时间限制: | 10.0s |
内存限制: | 256.0MB |
问题描述: | 样例输入 3 201711170032 201711222352 样例输出 201711170700 get_up |
问题连接: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;
}