Crontab

Crontab

  • 首先声明这个代码不是本文写的
  • 作者在代码的基础中加入注释
  • 列出c++作者认为比较重要的知识点,以注释的形式
  • 我觉得这个题目很经典,不难,但是考虑的方面很多
  • 每走一步都要小心

上代码:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<ctype.h>
#include<algorithm>
#include<set>
/**
    知识点1:
   int atoi(const char *nptr);
   从返回一个int类型的数
    string a="123";
   a.c_str();
   cout<<atoi(a.c_str());

   知识点2:
   判断一个字符是不是数字:
   string a="23";
   bool flag=isdigit(a[0]);
   判断一个字符是不是字母:
   bool isalpha(const char * this);

   知识点3:
   判断一个字符串是不是另一个字符串的子串:
   char *strstr(const char *str1, const char *str2):
   判断 str2 是不是str1的子串!!
   判断 str2 是不是str1的子串!!
   判断 str2 是不是str1的子串!!

    str1是长的!!

    返回第一个匹配的地址;
    string a="1111123123334";
    string b="23";
    string c=strstr(a.c_str(),b.c_str());
    cout<<c;
    //   23123334

    string a="1111123123334";
    string b="23";
    string c=strstr(a.c_str(),b.c_str());   // 注意 string 类型是惟一的!
    cout<<c<<endl;                          // 所以 c也是只存在一份(还是另一份!
    c[0]='8';                               // 所以改c[0]  不会改变我们的 长串a
    cout<<c<<endl;
    cout<<a;
    //23123334
    //83123334
    //1111123123334


    //char a[]="1234";                      !!!!!!!!!!!! 注意:::
    char c[]="23";
    char *d=strstr(a,c); ------ \           // 注意我们strstr函数的原型返回的是char *
    cout<<d<<endl;               \          // 同时指向的就是 长串a 的那一个位置!!
    d[0]='9'  ;                   \--------// 所以改变d[0] 也会改变  长串 a的那个位置!!!
    cout<<d<<endl;
    cout<<a;
    //234
    //923
    //1923

    知识点4:
    int getDayofWeek(int y,int m,int d){
        if(m==1||m==2){
            m+=12;
            y--;
        }
        return (d+2*m+3*(m+1)/5+y+y/4-y/100+y/400+1)%7;
    }
    这个函数太神奇了呀!! 不知道为什么!!

    知识点5:

*/
using namespace std;
/*
    1 jan
    2 feb
    3 mar
    4 apr
    5 may
    6 jun
    7 jul
    8 aug
    9 sep
    10 oct
    11 nov
    12 dec
    sun mon tue wed thu fri sat
*/
/// 这个想法很nb:
const char *month="janfebmaraprmayjunjulaugsepoctnovdec";
const char *weekday="sunmontuewedthufrisat";
int days[12]={31,28,31,30,31,30,31,31,30,31,30,31};

struct Command{
    int no; //编号
    long long time; //时间
    char name[105]; //名称
    bool operator < (const Command& rhs) const{
        if(time==rhs.time) return no<rhs.no;
        return time<rhs.time;
    }
    bool operator == (const Command& rhs) const{
        return strcmp(name,rhs.name)==0 && time==rhs.time;
    }
}command[10005];
int tot;//对执行命令计数

int n; //输入命令个数
long long startTime,finishTime; //开始时间和结束时间
char input[6][105]; //每条命令含有6个参数,type依次是【Minutes】【Hours】【day of month】【month】【day of week】【name】
set<int> timeRange[5];//时间值范围集合,type依次是【Minutes】【Hours】【day of month】【month】【day of week】
set<int>::iterator M,H,dm,m;//对应上一行的前4个迭代器

void getTimeRange(int type, char *str);//对input[type]获取时间值范围
int addTimeRange(int type, int start, int finish);//对timeRange[type]增加时间值范围
void addCommand();//对获取到的时间值范围添加命令
//工具类函数
int getValue(int &i, char *str);//从str[i]起得到一个时间值
long long getToday(int y,int m,int d);//计算今天的日期
int getDayofWeek(int y,int m,int d);//计算今天是星期几

int main(){
    scanf("%d%lld%lld",&n,&startTime,&finishTime);
    for(int i=0;i<n;i++){
        for(int j=0;j<5;j++) timeRange[j].clear();
        for(int j=0;j<6;j++){//读入每条命令的6个参数,并对前5个参数处理
            scanf("%s",input[j]);
            if(j!=5) getTimeRange(j,input[j]);
        }
        addCommand();
    }
    sort(command,command+tot);
    tot=unique(command,command+tot)-command;//忽略重复的
    for(int i=0;i<tot;i++)  printf("%lld %s\n",command[i].time,command[i].name);
    return 0;
}


void getTimeRange(int type, char *str){
    int start,finish;
    //处理星号表示的时间值范围
    if(str[0]=='*'){
        if(type==0) start=0, finish=59;
        else if(type==1) start=0, finish=23;
        else if(type==2) start=1, finish=31;
        else if(type==3) start=1, finish=12;
        else if(type==4) start=0, finish=6;
        addTimeRange(type,start,finish);
        return;
    }
    //处理横杠和逗号表示的时间值范围
    int i=0;
    int len=strlen(str);
    while(i<len){
        start=getValue(i,str);//获取一个值,如果后接'-',继续获取下一个值
        if(str[i]=='-') finish=getValue(++i,str);
        else finish=start;
        addTimeRange(type,start,finish);
    }
}

void addCommand(){
    long long today,time;
    int dayofWeek;
    int y1=startTime/1e8, y2=finishTime/1e8;
    int startDay=startTime/1e4;
    for(int y=y1;y<=y2;y++)//year
    for(m=timeRange[3].begin();m!=timeRange[3].end();m++)//month
    for(dm=timeRange[2].begin();dm!=timeRange[2].end();dm++){//day of month
        today=getToday(y,*m,*dm);//得到今天的日期
        if(today>=startDay && timeRange[4].count(getDayofWeek(y,*m,*dm))){//今天是星期几,是否在day of week中
            for(H=timeRange[1].begin();H!=timeRange[1].end();H++)//Hours
            for(M=timeRange[0].begin();M!=timeRange[0].end();M++){//Minutes
                time=today*1e4+(*H)*1e2+(*M);
                if(time>=startTime && time<finishTime){
                    strcpy(command[tot].name,input[5]);
                    command[tot].time=time;
                    command[tot].no=tot;
                    tot++;
                }
                else if(time>=finishTime) return;
            }
        }
    }
}

int getValue(int &i, char *str){
    char value[105];int cnt=0;
    int len=strlen(str);
    while(i<len){
        //如果是数值
        if(isdigit(str[i])){
            while(i<len && isdigit(str[i])){
                value[cnt++]=str[i++];
            }
            value[cnt]='\0';
            return atoi(value);
        }
        //如果是字母
        else if(isalpha(str[i])){
            while(i<len && isalpha(str[i])){
                value[cnt++]=tolower(str[i++]);
            }
            value[cnt]='\0';
            char *p=strstr(month,value);
            if(p) return (p-month)/3+1;
            else if(p=strstr(weekday,value)) return (p-weekday)/3;
        }
        else i++;
    }
    return -1;
}

int addTimeRange(int type,int start,int finish){
    for(int i=start;i<=finish;i++){
        timeRange[type].insert(i);
    }
}

long long getToday(int y,int m,int d){
    if(y%4==0 && y%100!=0 || y%400==0) days[1]=29;
    else days[1]=28;
    if(d>days[m-1]) return -1;
    return y*1e4+m*1e2+d;
}

int getDayofWeek(int y,int m,int d){
    if(m==1||m==2){
        m+=12;
        y--;
    }
    return (d+2*m+3*(m+1)/5+y+y/4-y/100+y/400+1)%7;
}

/*
输入:
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
*/

这个题目需要注意的点:

  • 如果按startime-finishtime的循环 逐渐加一秒或者逐渐加一天,这样的工作量很大很大。
  • 如果把范围的值存储开,我们循环可以取值的范围,这样的时间开销就会大大减少,这是代码的一个让我觉得nb的地方
  • 获取今天的日期这个函数我着实没看懂,很神奇,神奇!!
  • 我发现yyyymmdd这种的方式去存储时间很方便,很简单,值得推广!!今天看代码收获很大,希望能给你一些帮助,加油
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值