题目来源:http://118.190.20.162/view.page?gpid=T66
试题编号: |
201712-3 |
试题名称: |
Crontab |
时间限制: |
10.0s |
内存限制: |
256.0MB |
问题描述: |
样例输入 3 201711170032 201711222352 样例输出 201711170700 get_up |
------------------------------------------------------------
超级麻烦的大模拟。
最简单的做法是从起始时间到结束时间遍历每一分钟,逐条检查这个时间点是否满足规则,如果满足就输出。但是这样有可能会超时(没试过,不知道会不会超时,但根据题目给的测试数据规模看很可能会超时)。
因此变通一下,以“天”为单位遍历开始那天到结束那天,对于每一天,逐条检查其是否符合规则中
这个大模拟有两个重点:整体的数据结构、字符串操作。
·std::set<int> rule[25][5]: 将规则中的分/时/日/月/星期几的信息存储在set中,方便查询(find)操作。用迭代器遍历set可以生成所有时间点
·bool is_star[25][3]:对于涉及日期遍历的日/月/星期几信息,如果是星号,则不用查询即可知道一定满足规则,故设置is_star数组作为查询捷径
·struct Event ansList[10005]:结果结构体数组。结构体Event记录时间信息、匹配到的第几条规则(用于输出结果时按时间和规则号排序)、command命令字符串,并具有按日期遍历功能
出于运行速度的考虑没有使用STL string,只用了C语言的字符串处理函数。
strncpy字符串复制函数的用法值得一提。该函数头文件为"cstring",原型为
strncpy(char * Dst, char * Src, int n);
其中n为需要从Src中复制的字符串长度。使用时,建议将Dst字符串的长度设置为比需要复制的Src中的内容多一个char(用于存放结尾的’\0’),并将n设置为Dst的长度。下面一段代码可供参考:
char Src[20] = "Fri,Sat,Sun";
char Dst[4];
strncpy(Dst, Src+4, 4);
Dst[3] = '\0';
printf("%s", Dst);
诸如“判断闰年”“根据日期计算是星期几”的函数,不再赘述。
------------------------------------------------------------
// 遍历开始年初到结束年底的每一天,检查是否符合n条规则,
// 检查日月时用数组查找法
// 星期几单独检查,需要编写判断星期几的函数, 1970/01/01是thu
// 时分通过匹配到的规则中的时分数组生成
// 如果符合就放到结果结构体数组
// 最后连同起始时间、结束时间一起将结果数组排序,顺序输出排序结果
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include
#include
const char MONTH_NAME[13][4] = {"", "jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec"};
const char WEEKDAY_NAME[7][4] = {"sun","mon","tue","wed","thu","fri","sat"};
const int MONTH_DAY[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int n = 0, cnt = 0;
bool is_star[25][3] = {}; // 各条规则中“日”“月”“星期几”是否是"*"
std::set rule[25][5]; // 各条规则规定的时间条件数组,0-minutes, 1-hours, 2-day, 3-month, 4-week
char com[25][101]; // 各条规定的命令字符串
inline bool is_runnian(int year) // 判断是否是闰年
{
if (year % 100 == 0)
{
if (year % 400 == 0)
{
return true;
}
else
{
return false;
}
}
else if (year % 4 == 0)
{
return true;
}
else
{
return false;
}
}
struct Event {
int year, month, date, hour, minute;
int ind; // 匹配到的crontab命令的编号(用于输出排序)
char command[101];
Event(void): year(0), month(0), date(0), hour(0), minute(0), ind(-2)
{
strcpy(command, "");
}
Event(int yy, int mm, int dd, int hh, int min, int ii, char cc[101]):
year(yy), month(mm), date(dd), hour(hh), minute(min), ind(ii)
{
strcpy(command, cc);
}
Event(const Event & e):
year(e.year), month(e.month), date(e.date), hour(e.hour), minute(e.minute), ind(e.ind)
{
strcpy(command, e.command);
}
bool operator== (const Event & e) const
{
if (year == e.year && month == e.month && date == e.date && hour == e.hour && minute == e.minute && ind == e.ind
&& strcmp(command, e.command) == 0)
{
return true;
}
else
{
return false;
}
}
bool operator!= (const Event & e) const
{
if (year == e.year && month == e.month && date == e.date && hour == e.hour && minute == e.minute && ind == e.ind
&& strcmp(command, e.command) == 0)
{
return false;
}
else
{
return true;
}
}
bool operator< (const Event &e) const
{
if (year < e.year)
{
return true;
}
else if (year == e.year)
{
if (month < e.month)
{
return true;
}
else if (month == e.month)
{
if (date < e.date)
{
return true;
}
else if (date == e.date)
{
if (hour < e.hour)
{
return true;
}
else if (hour == e.hour)
{
if (minute < e.minute)
{
return true;
}
else if (minute == e.minute)
{
if (ind < e.ind)
{
return true;
}
}
}
}
}
}
return false;
}
void print() // 按题目要求的格式打印结果
{
printf("%04d%02d%02d%02d%02d %s\n", year, month, date, hour, minute, command);
}
void addOneDay() // 增加一天,用于遍历日期
{
int date_end;
if (is_runnian(year) && month == 2)
{
date_end = 29;
}
else
{
date_end = MONTH_DAY[month];
}
if (date == date_end)
{
if (month == 12)
{
year++;
month = 1;
date = 1;
}
else
{
month ++;
date = 1;
}
}
else
{
date ++;
}
}
int day_compare(const Event & e) const // 仅比较日期,用于日期遍历
{
if (year < e.year)
{
return -1;
}
else if (year > e.year)
{
return 1;
}
else
{
if (month < e.month)
{
return -1;
}
else if (month > e.month)
{
return 1;
}
else
{
if (date < e.date)
{
return -1;
}
else if (date > e.date)
{
return 1;
}
else
{
return 0;
}
}
}
}
} ansList[10005]; // 结果数组
int which_day (int year, int month, int day) // 输入日期计算星期几, 1970/01/01是星期一
{
int days = 0, i;
for (i=1970; i ans;
int i = 0, j = 0, k = 0, len = strlen(str), num = 0, prenum = 0;
char numstr[4];
bool flag = false; // '-'号标记
int is_char = -1; // 字符串首字母的位置,如果不是字符串则 = -1
if (strcmp(str, "*") == 0)
{
if (type == 0)
{
for (j=0; j<60; j++)
{
ans.insert(j);
}
}
else if (type == 1)
{
for (j=0; j<24; j++)
{
ans.insert(j);
}
}
else
{
is_star[ind][type-2] = true;
}
}
else
{
num = 0;
for (i=0; i= '0' && str[i] <= '9')
{
num = num *10 + (str[i] - '0');
}
else if (str[i] == ',')
{
if (is_char != -1)
{
strncpy(numstr, str+is_char, 4);
numstr[3] = '\0';
if (type == 3)
{
for (k=1; k<=12; k++)
{
if (strcmp(numstr, MONTH_NAME[k]) == 0)
{
num = k;
}
}
}
else if (type == 4)
{
for (k=0; k<7; k++)
{
if (strcmp(numstr, WEEKDAY_NAME[k]) == 0)
{
num = k;
}
}
}
}
is_char = -1;
if (flag)
{
flag = false;
for (j=prenum; j<=num; j++)
{
ans.insert(j);
}
}
else
{
ans.insert(num);
}
num = 0;
}
else if (str[i] == '-')
{
if (is_char != -1)
{
strncpy(numstr, str+is_char, 3);
if (type == 3)
{
for (k=1; k<=12; k++)
{
if (strcmp(numstr, MONTH_NAME[k]) == 0)
{
num = k;
}
}
}
else if (type == 4)
{
for (k=0; k<7; k++)
{
if (strcmp(numstr, WEEKDAY_NAME[k]) == 0)
{
num = k;
}
}
}
}
is_char = -1;
prenum = num;
flag = true;
num = 0;
}
else if (str[i] >= 'a' && str[i] <= 'z')
{
if (is_char == -1)
{
is_char = i;
}
}
else if (str[i] >= 'A' && str[i] <= 'Z')
{
if (is_char == -1)
{
is_char = i;
}
str[i] -= 'A';
str[i] += 'a';
}
}
// 对结尾的处理等同于逗号
if (is_char != -1)
{
strncpy(numstr, str+is_char, 3);
if (type == 3)
{
for (k=1; k<=12; k++)
{
if (strcmp(numstr, MONTH_NAME[k]) == 0)
{
num = k;
}
}
}
else if (type == 4)
{
for (k=0; k<7; k++)
{
if (strcmp(numstr, WEEKDAY_NAME[k]) == 0)
{
num = k;
}
}
}
}
is_char = -1;
if (flag)
{
flag = false;
for (j=prenum; j<=num; j++)
{
ans.insert(j);
}
}
else
{
ans.insert(num);
}
num = 0;
}
rule[ind][type] = ans;
}
void generate_ans_through_days(int year, int month, int day) // 给定特定的一天,判断是否符合n条规则,生成结果
{
int ind = 0; // 规则号
bool match = true; // 这一天是否满足这条规则
std::set::iterator it1, it2;
for (ind=0; ind=0; i--)
{
if (ansList[i] == end_time)
{
i_end = i;
break;
}
}
// 只输出start_time和end_time中间的结果
for (i=i_start+1; i