日期类与时间类问题
考点:模拟 、枚举
1.判断闰年
闰年满足的条件:
- 能被
4
整除且不能被100
整除 - 或者能被
400
整除
bool is_run(int year)
{
if((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) return true;
else return false;
}
2.日期合法判断
注:平年二月有28
天,闰年2月有29
天。
int days[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};// 平年2月有28天
// 判断该回文串是否为合理日期
bool check(int date)
{
int year = date / 10000;
int month = date / 100 % 100;
int day = date % 100;
if(month == 0 || month >= 13 || day == 0) return false;
if(month != 2 && day > days[month]) return false;
if(month == 2)// 2月特判
{
int leap = 0;// 0表示平年, 1表示闰年
if(leap_year(year))
leap = 1;
if(day > 28 + leap) return false;
}
return true;
}
int days[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};// 平年2月28天
bool is_run(int year)
{
if(year % 4 == 0 && year % 100 != 0 || year % 400 == 0) return true;
else return false;
}
// 判断日期是否合理(date:xxxx - xx - xx 年月日)
bool check(int date)
{
int year = date / 10000;
int month = date / 100 % 100;
int day = date % 100;
if(month == 0 || month >= 13 || day == 0) return false;// 初次判断月日是否合理
if(month != 2 && days > days[month]) return false;
if(month == 2)// 特判2月康康是闰年还是平年:闰年29天,平年28天
{
int leap = 0;
if(is_run(year))// 0表示平年, 1表示闰年
leap = 1;
if(day > 28 + leap) return false;
}
return true;
}
巩固练习——日期类
1. 回文日期
【题目链接】466. 回文日期 - AcWing题库
(枚举,模拟) O(10^4)
由于只有八位数,而且回文串左右对称,因此可以只枚举左半边,另一边通过翻转得到即可。这样只需枚举 0∼9999总共一万个数,然后判断:
- 整个八位数构成的日期是否合法;
- 是否在范围内
【代码实现】
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int days[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
bool is_run(int year)
{
if(year % 4 == 0 && year % 100 != 0 || year % 400 == 0) return true;
else return false;
}
bool check(int date)
{
int year = date / 10000;
int month = date / 100 % 100;
int day = date % 100;
if(month == 0 || month >= 13 || day == 0) return false;
if(month != 2 && day > days[month]) return false;
if(month == 2)// 特判2月
{
int leap = 0;
if(is_run(year))
leap = 1;
if(day > 28 + leap) return false;
}
return true;
}
int main()
{
int date1, date2;
cin >> date1 >> date2;
int res = 0;
for(int i = 1000; i <= 9999; i ++)
{
int date = i, tmp = i;
// 1.翻转拼接为日期形式
for(int j = 1; j <= 4; j ++) date = date * 10 + tmp % 10, tmp /= 10;
// 2.判断8位日期(已经是回文串)是否合理
if(date >= date1 && date <= date2 && check(date))
res ++;
}
cout << res;
return 0;
}
2.日期问题
【题目链接】1229. 日期问题 - AcWing题库
注意数据的读入和输出格式,推荐使用
scanf
和printf
思路:
枚举日期,判断是否满足题目的要即可,满足输出即可
- 在题目给的范围内枚举所有日期
- 判断是否满足日期个要求
- 再满足日期要求的前提下,判断是否符合题目所给的三种格式即可
【代码实现】
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int days[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
bool is_run(int year)
{
if(year % 4 == 0 && year % 100 != 0 || year % 400 == 0) return true;
else return false;
}
bool check(int date)
{
int year = date / 10000;
int month = date / 100 % 100;
int day = date % 100;
if(month == 0 || month >= 13 || day == 0) return false;
if(month != 2 && day > days[month]) return false;
if(month == 2)
{
int leap = 0;
if(is_run(year)) leap = 1;
if(day > leap + 28) return false;
}
return true;
}
int main()
{
int a, b, c;
scanf("%d/%d/%d", &a, &b, &c);
//枚举所有日期:日期都在1960年1月1日至2059年12月31日。
for(int i = 19600101; i <= 20592331; i ++)
{
int date = i;
if(check(date))// 检查日期合法性
{
int year = date / 10000, month = date / 100 % 100, day = date % 100;
//有采用年/月/日的,有采用月/日/年的,还有采用日/月/年的
if(year % 100 == a && month == b && day == c || // 年月日
month == a && day == b && year % 100 == c || // 月日年
day == a && month == b && year % 100 == c) // 日月年
{
// 不足两位会自动补0
printf("%d-%02d-%02d\n", year, month, day);
}
}
}
return 0;
}
3.回文日期
思路:同上题
【代码实现】
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int days[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};// 平年2月有28天
// 判断是否为ABABBABA形
bool check2(int date)
{
string s = to_string(date);
if(s[0] == s[2] && s[1] == s[3]) return true;
else return false;
}
// 判断闰年
bool leap_year(int year)
{
if(year % 4 == 0 && year % 100 != 0 || year % 400 == 0) return true;
else return false;
}
// 判断该回文串是否为合理日期
bool check(int date)
{
int year = date / 10000;
int month = date / 100 % 100;
int day = date % 100;
if(month == 0 || month >= 13 || day == 0) return false;
if(month != 2 && day > days[month]) return false;
if(month == 2)// 2月特判
{
int leap = 0;// 0表示平年, 1表示闰年
if(leap_year(year))
leap = 1;
if(day > 28 + leap) return false;
}
return true;
}
int main()
{
int date1;
cin >> date1;
int res1 = 0, res2;
for(int i = date1 % 10000 + 1; i < 10000; i ++)
{
int x = i, date = i;
for(int j = 0; j < 4; j ++) date = date * 10 + x % 10, x /= 10;// 将年份和年份的翻转拼接(一定是回文串)
if(date > date1 && check(date))
{
if(!res1) res1 = date;// 由于是顺序枚举,第一个就是所求的下一个
if(check2(date))//在回文日期的基础上:判断是否为ABABBABA
{
res2 = date;
break;
}
}
}
cout << res1 << endl << res2;
return 0;
}
巩固练习——时间类
1.航班时间
【题目链接】1231. 航班时间 - AcWing题库
本题的难点处理在于输入输出处理!
【代码实现】
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
// t1
// 去 :end1 - start1 = t + 时差
// t2
// 回 :end2 - start2 = t - 时差
// 2t = (t1 + t2)
//
int get_second(int h, int m, int sec)
{
return h * 3600 + m * 60 + sec;
}
int get_time()
{
string line;
getline(cin, line);
// 对应变化处理
if(line.back() != ')') line += "(+0)";
// 记住sscanf的用法
int h1, m1, s1, h2, m2, s2, d;
sscanf(line.c_str(), "%d:%d:%d %d:%d:%d (+%d)", &h1, &m1, &s1, &h2, &m2, &s2, &d);// 从字符串中获取信息
//将所有时间转化为距离当天(00:00:00)的秒数
return get_second(h2, m2, s2) - get_second(h1, m1, s1) + d * 24 * 3600;
}
int main()
{
int n;
scanf("%d", &n);
string line;
getline(cin, line);// 跳过首行的回车空格
while(n --)
{
// 求飞行时间
int t = (get_time() + get_time()) / 2;
// 格式变化
int hour = t / 3600;
int month = t % 3600 / 60;
int sec = t % 3600 % 60;
printf("%02d:%02d:%02d\n", hour, month, sec);
}
return 0;
}
2.时间显示
【题目链接】3416. 时间显示 - AcWing题库
对于时间,常用的方法就是模运算和除运算两种。
常用公式:
// time:这里的单位为s
hour = time / 3600;
min = time % 3600 / 60;
sec = time % 3600 % 60;
注:对于模运算的理解,相当于过滤掉不需要的秒数。
比如说min = time % 3600 / 60;相当于要求出分钟是多少,就要把属于小时的秒数都过滤掉(减去),然后再对剩下的秒数除以60,得到分钟数。
思路:
这道题有一点变形。**由于不需要显示年月日,因此给的秒数应该先过滤掉输入年月日的秒数。**即time % (24 * 60 * 60)
又有一点,给的不是秒数,而是毫秒,因此要先除以1000
变成秒数,再进行一系列操作。
【代码实现】
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
int main()
{
LL hao_miao;
cin >> hao_miao;
LL time = hao_miao / 1000;// 将毫秒变成秒
time = time % (24 * 60 * 60);// 过滤掉年月日的秒数
LL hour = time / 3600;
LL mi = time % 3600 / 60;
LL sec = time % 3600 % 60;
printf("%02lld:%02lld:%02lld", hour, mi, sec);
return 0;
}