样例输入

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

问题链接:CCF201712-3 Crontab

问题分析

这是一个模拟题,逻辑太复杂了。

一般而言,模拟题的关键在于数据表示,有了正确合理的数据表示,基本上就成功了。

编程采用自顶向下逐步细化的结构化编程思想。这样使得程序的每一个局部逻辑都变得简单易懂。

程序说明

结构Crontab的数组cmd[]是没有必要的,单变量就可以了。

用C++的pair类型是一种好的选择,用它来表示一个范围。任意的范围就用<-1,-1>来表示。从数学意义上说,pair类型可以称为序偶,其实其用途十分广泛。

分钟,小时,日,月份和星期,都有可能有若干个范围,所以用向量来存储是十分合适的。用数组表示也应该没有问题,只是数组要开得大一些,会浪费一部分存储。

程序中,很多代码是有关文本处理的。文本处理在CCF考试中非常常见,需要了然于心。

问题充满陷阱,比如月份和日期的简写,有可能是不规范(首字母大写,其他字母小写才是规范的)的,需要大小写转换后进行比较。不进行处理就比较只能得85分。

有关年月日算星期几的问题,用蔡勒公式进行计算是标准的,也可以用简易计算来替代。考试时一般来说写出相应的程序是困难的,似乎只能编写一个简单的替代函数代用一下。可以用模拟法来计算,逻辑也是比较麻烦的。

计算日期时间的组合是比较麻烦的事情,需要回溯。因为日期和时间各自的进制不同,不全是10进制,所以难以用循环计数进行处理,需要找到一种方法来解决。

程序中,尽可能把功能通用化,并且封装到函数中。

程序虽然比较长,但是各个部分的逻辑相似,局部还是比较简单的,写起来也比较容易。

代码不够简洁另外写了一版。

参考链接:

CCF201712-3 Crontab(100分)

题记

职业程序员通常追求程序的通用性。

提交后得100分的C++语言程序(简洁版)如下:

/* CCF201712-3 Crontab */#include <iostream>
#include <vector>
#include <queue>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>using namespace std;const char *weeks_months[]={"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
const int days[]={0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};int leapyear(int year, int month)
{if(month == 2)return ( ((year%4==0) && (year%100!=0)) || (year%400==0) ) ? 1 : 0;elsereturn 0;
}// Crontab
const int V = 5;
vector<pair<int, int> > v[V];   // 分别表示:分钟,小时,日,月份,星期
string cmd;struct CMD {int id;long long time;string cmd;bool operator < (const CMD &a) const //要按时间和先后顺序排好{return (time == a.time) ? id > a.id : time > a.time;}
};char buf[256];int getval(char t[])
{int i;t[0] = toupper(t[0]);for(i = 1; t[i]; i++)t[i] = tolower(t[i]);for(i = 0; i < 12 + 7; i++)if(strcmp(t, weeks_months[i]) == 0)break;if(i < 12 + 7)return i < 7 ? i : i - 6;elsereturn -1;
}void setsubval(char s[], vector<pair<int, int> >& v)
{int p1 = 0, p2 = 0;for(int i = 0; s[i]; i++)if(s[i] == '-') {s[i] = '\0';p2 = i + 1;break;}int val1, val2;if(p1 == p2) {if(isdigit(s[0]))val1 = atoi(s);elseval1 = getval(s);v.push_back(make_pair(val1, val1));} else {if(isdigit(s[0]))val1 = atoi(s);elseval1 = getval(s);if(isdigit(s[p2]))val2 = atoi(s + p2);elseval2 = getval(s + p2);v.push_back(make_pair(val1, val2));}
}void setval(char s[], vector<pair<int, int> >& v)
{if(s[0] == '*')v.push_back(make_pair(-1, -1));else {char *p = strtok(s, ",");while(p) {setsubval(p, v);p = strtok(NULL, ",");}}
}int myatoi(char t[], int b, int e)
{int v = 0;for(int i = b; i <= e; i++)v = v * 10 + t[i] - '0';return v;
}bool judge(int m, vector<pair<int, int> >& v)
{for(int i = 0; i < (int)v.size(); i++)if(v[i].first == -1 || (v[i].first <= m && m <= v[i].second))return true;return false;
}bool end_time_check(int y, int m, int d, int h, int mi, int ey, int em, int ed, int eh, int emi)
{if(y < ey) return true;if(m > em) return false;if(m < em) return true;if(d > ed) return false;if(d < ed) return true;if(h > eh) return false;if(h < eh) return true;if(mi > emi) return false;if(mi < emi) return true;return false;
}// 适用于1582年10月15日之后, 因为罗马教皇格里高利十三世在这一天启用新历法
// 蔡勒公式:给定年月日,得到当天是星期几
int weekday(int year,int month,int day)
{if(month == 1 || month == 2) {month += 12;year--;}int c = year / 100;int y = year % 100;int m = month;int d = day;int w = c / 4 - 2 * c + y + y / 4 + 26 * (m + 1) / 10 + d - 1;if(w < 0)return (w + (-w / 7 + 1) * 7) % 7;return w % 7;
}int main()
{int n;string s, t;priority_queue<CMD> q;cin >> n >> s >> t;strcpy(buf, s.c_str());int sy = myatoi(buf, 0, 3);int sm = myatoi(buf, 4, 5);int sd = myatoi(buf, 6, 7);int sh = myatoi(buf, 8, 9);int smi = myatoi(buf, 10, 11);strcpy(buf, t.c_str());int ey = myatoi(buf, 0, 3);int em = myatoi(buf, 4, 5);int ed = myatoi(buf, 6, 7);int eh = myatoi(buf, 8, 9);int emi = myatoi(buf, 10, 11);for(int i = 0; i < n; i++) {string ss;// 分别处理:分钟,小时,日,月份,星期for(int j = 0; j < V; j++) {v[j].clear();cin >> ss;strcpy(buf, ss.c_str());setval(buf, v[j]);}// Commandcin >> cmd;int k = sm, l = sd, m = sh, n = smi;    // 分别作为月份、日、小时和分钟的循环变量for(int j = sy; j <= ey; j++, k=1)  // 年循环处理for(; k <= 12; k++, l = 1)if(judge(k, v[3]))for(; l <= days[k] + leapyear(j, k); l++, m = 0)if(judge(l, v[2]) && judge(weekday(j, k, l), v[4]))for(; m < 24; m++, n = 0)if(judge(m, v[1]))for(; n < 60; n++) {if(!end_time_check(j, k, l, m, n, ey, em, ed, eh, emi))break;if(judge(n, v[0])) {CMD tmp;tmp.id = i;tmp.time = (long long)j * 100000000 + (long long)k * 1000000 + (long long)l * 10000 + (long long)m * 100 + n;tmp.cmd = cmd;q.push(tmp);}}}while(!q.empty()) {CMD tmp = q.top();q.pop();cout << tmp.time << " " << tmp.cmd << endl;}return 0;
}

提交后得100分的C++语言程序如下:

/* CCF201712-3 Crontab */#include <iostream>
#include <vector>
#include <queue>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>using namespace std;const char *months[]={"", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
const char *weeks[]={"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
const int days[]={0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};int leapyear(int year, int month)
{if(month == 2)return ( ((year%4==0) && (year%100!=0)) || (year%400==0) ) ? 1 : 0;elsereturn 0;
}const int N = 20;struct Crontab {vector<pair<int, int> > mi;  // 分钟vector<pair<int, int> > h;  // 小时vector<pair<int, int> > d;  // 天数vector<pair<int, int> > m;  // 月份vector<pair<int, int> > w;  // 星期string cmd;
} cmd[N];struct CMD {int id;long long time;string cmd;bool operator < (const CMD &a) const //要按时间和先后顺序排好{return (time == a.time) ? id > a.id : time > a.time;}
};char buf[256];int getval(char t[])
{int i;t[0] = toupper(t[0]);for(i = 1; t[i]; i++)t[i] = tolower(t[i]);for(i = 1; i <= 12; i++)if(strcmp(t, months[i]) == 0)break;if(i <= 12)return i;else {for(i = 0; i <= 6; i++)if(strcmp(t, weeks[i]) == 0)break;if(i <= 6)return i;}return -1;
}void setsubval(char s[], vector<pair<int, int> >& v)
{int p1 = 0, p2 = 0;for(int i = 0; s[i]; i++)if(s[i] == '-') {s[i] = '\0';p2 = i + 1;break;}int val1, val2;if(p1 == p2) {if(isdigit(s[0]))val1 = atoi(s);elseval1 = getval(s);v.push_back(make_pair(val1, val1));} else {if(isdigit(s[0]))val1 = atoi(s);elseval1 = getval(s);if(isdigit(s[p2]))val2 = atoi(s + p2);elseval2 = getval(s + p2);v.push_back(make_pair(val1, val2));}
}void setval(char s[], vector<pair<int, int> >& v)
{if(s[0] == '*')v.push_back(make_pair(-1, -1));else {char *p = strtok(s, ",");while(p) {setsubval(p, v);p = strtok(NULL, ",");}}
}int myatoi(char t[], int b, int e)
{int v = 0;for(int i = b; i <= e; i++)v = v * 10 + t[i] - '0';return v;
}bool judge(int m, vector<pair<int, int> >& v)
{for(int i = 0; i < (int)v.size(); i++)if(v[i].first == -1 || (v[i].first <= m && m <= v[i].second))return true;return false;
}bool end_time_check(int y, int m, int d, int h, int mi, int ey, int em, int ed, int eh, int emi)
{if(y < ey) return true;if(m > em) return false;if(m < em) return true;if(d > ed) return false;if(d < ed) return true;if(h > eh) return false;if(h < eh) return true;if(mi > emi) return false;if(mi < emi) return true;return false;
}// 适用于1582年10月15日之后, 因为罗马教皇格里高利十三世在这一天启用新历法
// 蔡勒公式:给定年月日,得到当天是星期几
int weekday(int year,int month,int day)
{if(month == 1 || month == 2) {month += 12;year--;}int c = year / 100;int y = year % 100;int m = month;int d = day;int w = c / 4 - 2 * c + y + y / 4 + 26 * (m + 1) / 10 + d - 1;if(w < 0)return (w + (-w / 7 + 1) * 7) % 7;return w % 7;
}int main()
{int n;string s, t;priority_queue<CMD> q;cin >> n >> s >> t;strcpy(buf, s.c_str());int sy = myatoi(buf, 0, 3);int sm = myatoi(buf, 4, 5);int sd = myatoi(buf, 6, 7);int sh = myatoi(buf, 8, 9);int smi = myatoi(buf, 10, 11);strcpy(buf, t.c_str());int ey = myatoi(buf, 0, 3);int em = myatoi(buf, 4, 5);int ed = myatoi(buf, 6, 7);int eh = myatoi(buf, 8, 9);int emi = myatoi(buf, 10, 11);for(int i = 0; i < n; i++) {string ss;// 分钟cin >> ss;strcpy(buf, ss.c_str());setval(buf, cmd[i].mi);// 小时cin >> ss;strcpy(buf, ss.c_str());setval(buf, cmd[i].h);// 天数cin >> ss;strcpy(buf, ss.c_str());setval(buf, cmd[i].d);// 月份cin >> ss;strcpy(buf, ss.c_str());setval(buf, cmd[i].m);// 周cin >> ss;strcpy(buf, ss.c_str());setval(buf, cmd[i].w);// Commandcin >> cmd[i].cmd;int k = sm, l = sd, m = sh, n = smi;for(int j = sy; j <= ey; j++, k=1)for(; k <= 12; k++, l = 1)if(judge(k, cmd[i].m))for(; l <= days[k] + leapyear(j, k); l++, m = 0)if(judge(l, cmd[i].d) && judge(weekday(j, k, l), cmd[i].w))for(; m < 24; m++, n = 0)if(judge(m, cmd[i].h))for(; n < 60; n++) {if(!end_time_check(j, k, l, m, n, ey, em, ed, eh, emi))break;if(judge(n, cmd[i].mi)) {CMD tmp;tmp.id = i;tmp.time = (long long)j * 100000000 + (long long)k * 1000000 + (long long)l * 10000 + (long long)m * 100 + n;tmp.cmd = cmd[i].cmd;q.push(tmp);}}}while(!q.empty()) {CMD tmp = q.top();q.pop();cout << tmp.time << " " << tmp.cmd << endl;}return 0;
}

CCF201712-3 Crontab(100分)【模拟+文本处理】相关推荐

  1. CCF201709-3 JSON查询(100分)【文本处理】

    问题描述 JSON (JavaScript Object Notation) 是一种轻量级的数据交换格式,可以用来描述半结构化的数 据.JSON 格式中的基本单元是值 (value),出于简化的目的本 ...

  2. CCF201903-4 消息传递接口(100分)【模拟】

    试题编号: 201903-4 试题名称: 消息传递接口 时间限制: 1.0s 内存限制: 512.0MB 问题链接:CCF201903-4 消息传递接口 问题简述:(略) 问题分析:模拟题,比较费时间 ...

  3. CCF201712-2 游戏(100分)【模拟】

    试题编号: 201712-2 试题名称: 游戏 时间限制: 1.0s 内存限制: 256.0MB 问题描述: 问题描述 有n个小朋友围成一圈玩游戏,小朋友从1至n编号,2号小朋友坐在1号小朋友的顺时针 ...

  4. CCF201512-1 数位之和(100分)【进制+文本】

    试题编号: 201512-1 试题名称: 数位之和 时间限制: 1.0s 内存限制: 256.0MB 问题描述: 问题描述 给定一个十进制整数n,输出n的各位数字之和. 输入格式 输入一个整数n. 输 ...

  5. CCF202006-3 Markdown渲染器(100分)【文本处理】

    试题编号: 202006-3 试题名称: Markdown渲染器 时间限制: 1.0s 内存限制: 512.0MB 问题链接:CCF202006-3 Markdown渲染器 问题简述:(略) 问题分析 ...

  6. CCF201912-4 区块链(100分)【模拟】

    试题编号: 201912-4 试题名称: 区块链 时间限制: 10.0s 内存限制: 512.0MB 问题链接:CCF201912-4 区块链 问题简述:(略) 问题分析:模拟题,不解释. 程序说明: ...

  7. CCF201909-4 推荐系统(100分)【模拟】

    试题编号: 201909-4 试题名称: 推荐系统 时间限制: 5.0s 内存限制: 512.0MB 问题链接:CCF201909-4 推荐系统 问题简述:(略) 问题分析:模拟题,不解释. 程序说明 ...

  8. CCF201912-3 化学方程式(100分)【文本处理】

    试题编号: 201912-3 试题名称: 化学方程式 时间限制: 1.0s 内存限制: 512.0MB 问题链接:CCF201912-3 化学方程式 问题简述:(略) 问题分析:文本处理问题,按字符串 ...

  9. CCF201809-3 元素选择器(100分)【文本处理】

    试题编号: 201809-3 试题名称: 元素选择器 时间限制: 1.0s 内存限制: 256.0MB 问题链接:CCF201809-3 元素选择器 问题简述:(略) 问题分析:文本处理问题,需要有好 ...

最新文章

  1. 计蒜客NOIP模拟赛(2) D2T2紫色百合
  2. linux搭建宝塔重启mysql_宝塔面板安装 重启等命令linux系统重启
  3. 小型动漫知识图谱的构建 (Python+Neo4j) (纯实践内容,基于bilibili所有正版番剧的动漫、声优、角色、类型)
  4. java中解密技术是什么_详解Java 加密解密技术的分类和归纳
  5. 编译生成的Apk安装到手机提示应用未安装,需给apk签名
  6. python response重头开始_用 Python 抓取公号文章保存成 PDF
  7. Consider the following: If you want an embedded database (H2, HSQL or Der...
  8. #include 和前置声明
  9. 卷积神经网络之“浅层特征”与“深层特征”
  10. win7的计算机最大连接数,win7系统解除共享文件夹最大连接数限制的操作方法
  11. Nicholas C. Zakas:最佳职业生涯建议
  12. 使用auto.js模拟手动点击芭芭农场任务(芭芭农场自动脚本2022.8.1更新)
  13. 【图像修复】基于滤波实现损坏图像修复含Matlab源码
  14. C# WAV音乐多音轨合并
  15. 如何下载tomcat各个版本
  16. 小程序定位,接入腾讯位置服务
  17. 服务器文件夹只读属性去不掉,C# 去除文件或 文件夹只读属性
  18. LINUX暂停、挂起进程,开启进程
  19. jenkin+maven+git构建项目
  20. 阿里云王牌架构师一问开发者:系统要改造成微服务吗

热门文章

  1. GDAL插值使用示例
  2. SQL那些事儿(八)--oracle用户、表、表空间之间的关系
  3. Golang使用心得
  4. 25个优秀的UI设计资源下载
  5. Flashdevelop解决ANE报Not supported native extensions profile
  6. DXUT框架剖析系列文章(原创:天行健 君子当自强而不息)
  7. C#中实现byte[]与任意对象互换(服务端通讯专用)
  8. 用C#读取数码相片的EXIF信息(一)
  9. 如何打开电脑就自动显示html文件,电脑教程:Win10怎么打开html文件
  10. python数据分析与展示 嵩天_Python数据分析与展示第2周学习笔记(北理工 嵩天)...