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这种的方式去存储时间很方便,很简单,值得推广!!今天看代码收获很大,希望能给你一些帮助,加油