CSP 201712-3 Crontab(0→85→95→100)

CSP 201712-3 Crontab 0→85→95→100

3 Crontab

tag:复杂模拟 字符串 日期

题面链接

http://118.190.20.162/view.page?gpid=T66.

题意

  题目为任务的调度问题,个人感觉跟平常使用的日历中的日程计划比较类似。题目会给出多个任务以及该任务的执行时间,时间有可能是重复性的,我们需要做的就是按照时间先后输出执行的所有任务。

思路

   采取构造的方式:对于给定任务,构造所有会执行的时间,用数据结构map(时间:任务列表)进行存储,由于map本身是有序的,所以处理完所有任务后,遍历map输出即可。
  问题转化为如何构造给定任务的所有执行时间,可以先求出分钟、小时、日、月、星期的可行时间,然后进行组合,组合出yyyymmddHHMM格式的日期,其中星期由于没有显式位于日期中,因此采取对组合后的日期进行星期验证的方式保证星期的可行性。另外对于“*”即任意的情况,采取将取值范围内所有值均加入的方式进行处理,但因为构造日期可能不位于给定起始日期s,终止日期t之间、不同月份天数不同的问题可能出现非法日期(比如:0231,2月31日)等原因,所以对于构造的日期需要进一步进行检验保证其正确性。
   需要注意的几个细节如下:

1.csp 编译器比较古老,不支持一些函数如stoi、tostring的使用;(0分:编译错误)
2.月份、星期的英文缩写不区分大小写;(85分)
3.可能存在区间重合问题,比如:3,1-5 如不特殊考虑,则3就构造多次,导致出错。(95分)

源码

#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
typedef long long ll;
map<string,vector<string> >mp;//时间:指令
map<string,vector<string> >::iterator iter;//迭代器
map<string,string> mpchar_num;//英文:数字。比如,Jan:01,Sun:00
map<string,string> mp_week;//时间:周
typedef struct {
    int year,month,day,hour,minutes;
}node;
node start,endt;
string g_s,g_t,sminute,shour,sday,smonth,sweek,instructment;

//ccf编译器不支持 my_stoi,my_to_string:进行转化
int my_stoi(string s){
    return atoi(s.c_str());
}

string my_to_string(int i){
    char str[10];
    itoa(i,str,10);
    return str;
}


//将字符串s处理为v
void funs_v(string s,vector<string> &v,int j_start,int j_end){
    v.clear();
    string s1="",s2="";
    char str[5];
    //遍历s
    for(int i=0;i<s.size();i++){
        //任意符
        if(s[i]=='*'){
            for(int j=j_start;j<=j_end;j++){
                sprintf(str,"%02d",j);
                if(find(v.begin(),v.end(),str)==v.end()) v.push_back(str);
            }
            break;
        }
        //,号
        if(s[i]==','){
            int j=my_stoi(s1);sprintf(str,"%02d",j);
            if(find(v.begin(),v.end(),str)==v.end()) v.push_back(str);
            s1="";continue;
        }
        //-号
        if(s[i]=='-'){
            //s1-s2
            for(i++;i<s.size();i++){
                if(s[i]==',')break;
                s2+=s[i];
            }
            int sj=my_stoi(s2);
            for(int j=my_stoi(s1);j<=sj;j++){
                sprintf(str,"%02d",j);
                if(find(v.begin(),v.end(),str)==v.end()) v.push_back(str);
            }
            //s1,s2清零
            s1="";s2="";continue;
        }
        //else:数字
        s1+=s[i];
    }
    if(s1!="") {
        int j=my_stoi(s1);
        sprintf(str,"%02d",j);
        if(find(v.begin(),v.end(),str)==v.end()) v.push_back(str);
    }
}

//将月份和周中的英文缩写处理为数字
string funchar_num(string s){
    string ans="",s1="";
    for(int i=0;i<s.size();i++){
        //小写字母
        if(s[i]>='a' && s[i]<='z'){
            s1+=s[i];continue;
        }
        //大写字母转为小写
        if(s[i]>='A' && s[i]<='Z'){
            s1+=(s[i]-'A'+'a');continue;
        }
        if(s1!=""){ans+=mpchar_num[s1];s1="";}
        ans+=s[i];
    }
    if(s1!=""){ans+=mpchar_num[s1];s1="";}
    return ans;
}

//获取某年某月的天数
int month_day[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
int get_day(int year,int month){
    //cout<<year<<" "<<month<<endl;
    if(month!=2) return month_day[month];
    //若是闰年
    if((year%4==0 && year%100!=0) || year%400==0) return month_day[month]+1;
    return month_day[month];
}

//检查日期是否满足要求
bool check(string s){
    //不在起止时间内
    if(s<g_s || s>=g_t) return false;
    //在起止时间内,判断日期合法性(月份,日)
    //201711170032
    //获取年、月、日
    int c_year=0,c_month=0,c_day=0;
    c_year=my_stoi(s.substr(0,4));
    c_month=my_stoi(s.substr(4,2));
    c_day=my_stoi(s.substr(6,2));
    if(c_day<=get_day(c_year,c_month)) return true;
    return false;
}

//添加指令
void solve(){
    vector<string> vminute,vhour,vday,vmonth,vweek;
    //处理分钟
    funs_v(sminute,vminute,0,59);
    //处理小时
    funs_v(shour,vhour,0,23);
    //处理日
    funs_v(sday,vday,1,31);
    //处理月
    smonth=funchar_num(smonth);
    funs_v(smonth,vmonth,1,12);
    //处理周
    sweek=funchar_num(sweek);
    funs_v(sweek,vweek,0,6);
    //cout<<sweek<<endl;
    //从年到月、日、时、分构造完整时间
    for(int year=start.year;year<=endt.year;year++){
        for(int month=0;month<vmonth.size();month++){
            for(int day=0;day<vday.size();day++){
                for(int hour=0;hour<vhour.size();hour++){
                    for(int minute=0;minute<vminute.size();minute++){
                        string time="";
                        time+=my_to_string(year);time+=vmonth[month];time+=vday[day];time+=vhour[hour];time+=vminute[minute];
                        //判断time是否符合要求  &&  是否满足该周几
                        //cout<<time.substr(0,8)<<" "<<mp_week[time.substr(0,8)]<<endl;
                        if(find(vweek.begin(), vweek.end(), mp_week[time.substr(0,8)]) != vweek.end() ){
                            if(check(time)){
                                mp[time].push_back(instructment);
                                //cout<<instructment<<endl;
                            }
                        }
                    }
                }
            }
        }
    }

}

//mpchar_num,mp_week的初始化
void initial(){
    //初始化mpchar_num
    string s_month[]={"jan", "feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec"};
    string s_week[]={"sun", "mon","tue","wed","thu","fri","sat"};
    for(int i=0;i<12;i++) mpchar_num[s_month[i]]=my_to_string(i+1);
    for(int i=0;i<7;i++) mpchar_num[s_week[i]]=my_to_string(i);
    //初始化mp_week
    int week=4;//1970年1月1日:周四
    string time="";
    char str[5];
    for(int year=1970;year<=2100;year++){
        for(int month=1;month<=12;month++){
            int all_day=get_day(year,month);
            for(int day=1;day<=all_day;day++){
                //构造time
                time=my_to_string(year);
                sprintf(str,"%02d",month);
                time+=str;
                sprintf(str,"%02d",day);
                time+=str;
                //计算周次
                week%=7;
                sprintf(str,"%02d",week);
                mp_week[time]=str;
                week++;
                //cout<<time<<"  "<<str<<endl;
            }
        }
    }

}
int main() {
    int n;
    initial();
    cin>>n>>g_s>>g_t;
    //字符串转数字
    start.year=my_stoi(g_s.substr(0,4));start.month=my_stoi(g_s.substr(4,2));
    start.day=my_stoi(g_s.substr(6,2));start.hour=my_stoi(g_s.substr(8,2));
    start.minutes=my_stoi(g_s.substr(10,2));

    endt.year=my_stoi(g_t.substr(0,4));endt.month=my_stoi(g_t.substr(4,2));
    endt.day=my_stoi(g_t.substr(6,2));endt.hour=my_stoi(g_t.substr(8,2));
    endt.minutes=my_stoi(g_t.substr(10,2));

    while(n--){
        cin>>sminute>>shour>>sday>>smonth>>sweek>>instructment;
        solve();
    }
    //遍历map,输出结果
    for(iter=mp.begin();iter!=mp.end();iter++){
        for(int i=0;i<iter->second.size();i++){
            cout<<iter->first<<" "<<iter->second[i]<<'\n';
        }
    }
    return 0;
}
/*
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
 */
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值