CCF CSP Crontab

本文介绍了一种高效遍历配置文件的方法,并提供了一个完整的C++实现案例。通过将配置信息按时间分类,可以快速确定哪些配置适用于指定的时间段,进而提高了处理效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这道题目可以从以下几点来分析,遍历给定起点到终点的每一分钟,然后去配置文件中查找,但是这样会超时,我们转化一下思路,遍历配置文件中的时间,根据产生的日期检查其是否有效,这样检查的时间大大减少。

工具函数准备

利用stringstream实现string和int之间的相互转化。

string int_to_string(int a){
    /**
     * 将给定的整数变为字符串
     */
    ostringstream ostringstream1;
    ostringstream1<<a; // 将a写入流中
    return ostringstream1.str(); // 从流中获取到对应的整数
}

int string_to_int(const string & str){
    /**
     * 将给定的字符串变为整数
     */
    int num;
    istringstream ss(str);
    ss >> num;
    return num;
}

计算给定时间是星期几

题目中给出我们1970-01-01是星期四,我们只要算出给定时间到这个基准时间的天数,然后就可以算出是星期几了。

int getweek(const string & date){
    /**
     * date的格式是 yyyymmddHHMM是一个长度为12的字符串
     * 根据1970-01-01是星期四开始推算
     */
    int yyyy = string_to_int(date.substr(0, 4));
    int mm = string_to_int(date.substr(4, 2));
    int dd = string_to_int(date.substr(6, 2));
    int HH = string_to_int(date.substr(8, 2));
    int MM = string_to_int(date.substr(10, 2));
    // 先算年
    int sum = 0;
    for (int i = 1970; i < yyyy; ++i) {
        sum += isLeap(i)?366:365;
    }
    // 再算月
    if (isLeap(yyyy)) Daysofmon[2] = 29;
    else Daysofmon[2] = 28;
    for (int i = 1; i < mm; ++i) {
        sum += Daysofmon[i];
    }
    // 再算日子
    sum += dd-1;
    return (4+sum)%7;
}

将每一条配置信息放到对应的vector中

string getweek(const string & cyyyy, const string & cmm, const string & cdd) {
    /**
     * date的格式是 yyyymmddHHMM是一个长度为12的字符串
     * 根据1970-01-01是星期四开始推算
     */
    int yyyy = string_to_int(cyyyy);
    int mm = string_to_int(cmm);
    int dd = string_to_int(cdd);
    // 先算年
    int sum = 0;
    for (int i = 1970; i < yyyy; ++i) {
        sum += isLeap(i) ? 366 : 365;
    }
    // 再算月
    if (isLeap(yyyy)) Daysofmon[2] = 29;
    else Daysofmon[2] = 28;
    for (int i = 1; i < mm; ++i) {
        sum += Daysofmon[i];
    }
    // 再算日子
    sum += dd - 1;
    return int_to_string((4 + sum) % 7);
}

最后贴上全部代码

#include <bits/stdc++.h>

using namespace std;
char Month[][4]={"","jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec"};
char Week[][4]={"sun","mon","tue","wed","thu","fri","sat"};
int Daysofmon[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
map<string, int> weekmap, monthmap;
int n;
map<string, vector<string> > map1;
string int_to_string(int a) {
    /**
     * 将给定的整数变为字符串
     */
    ostringstream ostringstream1;
    ostringstream1 << a; // 将a写入流中
    return ostringstream1.str(); // 从流中获取到对应的整数
}

int string_to_int(const string &str) {
    /**
     * 将给定的字符串变为整数
     */
    int num;
    istringstream ss(str);
    ss >> num;
    return num;
}

bool isLeap(int year) {
    return (year % 400 == 0) || (year % 100 != 0 && year % 4 == 0);
}

string getweek(const string & cyyyy, const string & cmm, const string & cdd) {
    /**
     * date的格式是 yyyymmddHHMM是一个长度为12的字符串
     * 根据1970-01-01是星期四开始推算
     */
    int yyyy = string_to_int(cyyyy);
    int mm = string_to_int(cmm);
    int dd = string_to_int(cdd);
    // 先算年
    int sum = 0;
    for (int i = 1970; i < yyyy; ++i) {
        sum += isLeap(i) ? 366 : 365;
    }
    // 再算月
    if (isLeap(yyyy)) Daysofmon[2] = 29;
    else Daysofmon[2] = 28;
    for (int i = 1; i < mm; ++i) {
        sum += Daysofmon[i];
    }
    // 再算日子
    sum += dd - 1;
    return int_to_string((4 + sum) % 7);
}

void initmap() {
    for (int i = 0; i <= 6; ++i) {
        weekmap[Week[i]] = i;
    }
    for (int i = 1; i <= 12; ++i) {
        monthmap[Month[i]] = i;
    }
}
void tostandard(string & str){
    for (int i = 0; i < str.size(); ++i) {
        if (isalpha(str[i]))
            str[i] = tolower(str[i]);
    }
}

vector<string> buildvector(string &str, int type = 0) {
    /**
     * type一共三种,当key为1是,表示建立week,当key为2时,表示建立month
     * 其他的为0
     */
    vector<string> retvec;
    str += ",";
    int ix;
    while ((ix = str.find(',')) != string::npos) {
        //查找-
        string temp = str.substr(0, ix);
        str = str.substr(ix + 1);
        int fx;
        if ((fx = temp.find('-')) != string::npos) {//说明是连续的数
            string ls = temp.substr(0, fx);
            string rs = temp.substr(fx + 1);
            int lix, rix;
            if (isalpha(ls[0])) {
                if (type == 1) lix = weekmap[ls];
                else lix = monthmap[ls];
            } else lix = string_to_int(ls);

            if (isalpha(rs[0])) {
                if (type == 1) rix = weekmap[rs];
                else rix = monthmap[rs];
            } else rix = string_to_int(rs);
            // 这样都转化为整数
            for (int i = lix; i <= rix; ++i) {
                retvec.push_back(int_to_string(i));
            }
        } else {//说明是一个数
            if (isalpha(temp[0])) {
                // 说明需要转换
                if (type == 1) retvec.push_back(int_to_string(weekmap[temp]));
                else retvec.push_back(int_to_string(monthmap[temp]));
            } else
                retvec.push_back(temp);
        }
    }
    return retvec;
}

int main() {
//    freopen("../in.txt", "r", stdin);
    cin>>n;
    string stime, etime;
    cin>>stime>>etime;
    int syyyy = string_to_int(stime.substr(0, 4));
    int eyyyy = string_to_int(etime.substr(0, 4));
    initmap();
    while (n--){// 对每一条配置项进行解析
        string minutes, hours, day_of_month, month, day_of_week, command;

        cin>>minutes>>hours>>day_of_month>>month>>day_of_week>>command;
        tostandard(month);
        tostandard(day_of_week);
        if (minutes=="*") minutes="0-59";
        vector<string> vminutes = buildvector(minutes, 0);
        if (hours == "*") hours = "0-23";
        vector<string> vhours = buildvector(hours, 0);
        if (day_of_month == "*") day_of_month="1-31";
        vector<string> vday_of_month = buildvector(day_of_month, 0);
        if (month == "*") month = "1-12";
        vector<string> vmonth = buildvector(month, 2);
        if (day_of_week == "*") day_of_week="0-6";
        vector<string> vday_of_week = buildvector(day_of_week, 1);
        set<string> set1(vday_of_week.begin(), vday_of_week.end());
        // 对前面的四项进行遍历,然后根据星期几和时间的合法性进行取舍
        //从当前年开始遍历
        int tempyyyy = syyyy;
        while (tempyyyy<=eyyyy){
            if (isLeap(tempyyyy)) Daysofmon[2] = 29;
            else Daysofmon[2] = 28;
            for (int i = 0; i < vmonth.size(); ++i) {
                for (int j = 0; j < vday_of_month.size(); ++j) {
                    string cyyyy = int_to_string(tempyyyy);
                    string cmm = vmonth[i];
                    string cdd = vday_of_month[j];
                    // 这个判断是最重要的一部分的
                    if (Daysofmon[string_to_int(cmm)]<string_to_int(cdd)||set1.count(getweek(cyyyy, cmm, cdd))==0) continue;
                    for (int k = 0; k < vhours.size(); ++k) {
                        for (int m = 0; m < vminutes.size(); ++m) {

                            string ss = cyyyy+(cmm.size()>1?cmm:"0"+cmm)+(cdd.size()>1?cdd:"0"+cdd)
                                        +(vhours[k].size()>1?vhours[k]:"0"+vhours[k])+(vminutes[m].size()>1?vminutes[m]:"0"+vminutes[m]);

                            if (ss>=stime&&ss<etime){
                                map1[ss].push_back(command);
                            }
                        }
                    }
                }
            }
            tempyyyy++;
        }
    }
    // 全部结束之后开始打印结果
    map<string , vector<string> >::iterator it = map1.begin();
    for (; it!=map1.end(); it++){
        set<string> set1;
        for (int i = 0; i < it->second.size(); ++i) {
            if (set1.count(it->second[i])==0){
                cout<<it->first<<" "<<it->second[i]<<endl;
                set1.insert(it->second[i]);
            }
        }
    }
}

主要参考了这篇博客:
传送门

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值