题目链接: AcWing 1229 日期问题
题意: 输入$A,B,C$三个两位的数字,代表的意义可能是年/月/日或月/日/年或日/月/年,其中年是年份的尾数,找出可能代表的合法日期,输出在$1960$年$1$月$1$日至$2059$年$12$月$31$日之间的日期
解题思路:
- 这是一道典型的模拟题,就是按照题目说的意思去做就行
- 要输出一个日期,这个日期必须满足:1. 这个日期是合法的(存在这个日期);2. 这个日期在规定范围内
- 因为答案最多只有三个,而且$A,B,C$如何排列都已经事先知道了,所以只需要定义一个$check(year,month,day)$函数,用来判断传入的年月日是否符合规定,分别把三种排列输入函数内,若合法,则保存下来
注意事项:
- 输入输出的格式要处理
- 合法日期可能重复,需要去重
- 多个合法日期必须日期的从早到晚输出
- 去重和排序都可以定义一个变量$id$作为这个答案的唯一标识,$id=(year\times 100 + month) \times 100 + day$
代码如下:
#include <iostream>
#include <algorithm>
using namespace std;
// date 数组记录输入的三个数据
// cnt 记录合法的答案数量
int date[5], cnt;
int days[13] = {
0, 31, 28, 31,
30, 31, 30,
31, 31, 30,
31, 30, 31
};
char str[20];
// 存答案,最多只有三个答案
struct Ans {
int y, m, d;
int id;
} ans[3];
void check(int year, int mon, int day) {
// 按照年份后两位分配一个完整的年份
if (year >= 60) {
year = 1900 + year;
} else {
year = 2000 + year;
}
// 检查除了二月以外的月份和日期是否合法
if (mon > 12 || day < 1 || mon != 2 && day > days[mon]) {
return;
}
// 若月份为二月,则检查二月
// 要处理闰年问题
int leap = year % 400 == 0 || year % 100 && year % 4 == 0;
if (mon == 2 && day > days[mon] + leap) {
return;
}
// 若答案合法,就存入答案并计数
ans[cnt].y = year;
ans[cnt].m = mon;
ans[cnt].d = day;
ans[cnt].id = (year * 100 + mon) * 100 + day;
cnt++;
}
bool cmp(Ans &a, Ans &b) {
return a.id < b.id;
}
int main() {
// 处理输入,读入字符串,手动把数字抠出来
scanf("%s", str);
date[0] = (str[0] - '0') * 10 + str[1] - '0';
date[1] = (str[3] - '0') * 10 + str[4] - '0';
date[2] = (str[6] - '0') * 10 + str[7] - '0';
// 最多只有三种情况:
// 年月日
check(date[0], date[1], date[2]);
// 月日年
check(date[2], date[0], date[1]);
// 日月年
check(date[2], date[1], date[0]);
// 排序保证答案是从小到大排序的
sort(ans, ans + cnt, cmp);
for (int i = 0; i < cnt; i++) {
int y = ans[i].y;
int m = ans[i].m;
int d = ans[i].d;
// 去重
if (i && ans[i].id == ans[i - 1].id) {
continue;
}
// 处理输出格式
printf("%d-", y);
if (m < 10) {
printf("0%d-", m);
} else {
printf("%d-", m);
}
if (d < 10) {
printf("0%d\n", d);
} else {
printf("%d\n", d);
}
}
return 0;
}
读入的话直接
会更方便一些
if (i && ans[i].id == ans[i - 1].id) {
continue;
}
这里能确定第一个跟第二个不重复,能确定第二个跟三个不重复,但是确认不了第一个跟第三个是否重复吧
已经排过序了,比如说如果第一个和第三个重复,那第一个和第二个必定是重复的。反过来说,第一个和第二个不重复的话,第一个和第三个必定不重复。
谢谢大佬
读入可以
大佬,标记id判重为什么是ans[cnt].id = (year * 100 + mon) * 100 + day;这样呀?
让日期变成20240308这样的格式。
我去,太牛啦!Orz
我也是这么想的,直接判断给出的数据的三个可能输出,再判断合不合法即可。但是还需要排序,就有些麻烦了
太多干货了
谢谢,加油hh
里面太多细节了值得我学习了
加油hh
厉害
谢谢hh
..好像我对题目理解有问题
可你的代码的确过了..
我一开始也觉得只有三种…想了想 年月日 年日月 日月年 日年月 月年日 月日年 A33 = 6种..
看题目 题目明确规定了只有三种
只有三种,直接check三次就行,很多解法复杂化了