【蓝桥杯2020省赛】【模拟、穷举】回文日期(详解)

题目

2020 年春节期间,有一个特殊的日期引起了大家的注意:2020 年 2 月 2 日。因为如果将这个日期按 “yyyymmdd” 的格式写成一个 8 位数是 20200202,恰好是一个回文数。我们称这样的日期是回文日期。

有人表示 20200202 是 “千年一遇” 的特殊日子。对此小明很不认同,因为不到 2 年之后就是下一个回文日期:20211202 即 2021 年 12 月 2 日。

也有人表示 20200202 并不仅仅是一个回文日期,还是一个 ABABBABA 型的回文日期。对此小明也不认同,因为大约 100 年后就能遇到下一个 ABABBABA 型的回文日期:21211212 即 2121 年 12 月 12 日。算不上 “千年一遇”,顶多算 “千年两遇”。

给定一个 8 位数的日期,请你计算该日期之后下一个回文日期和下一个 ABABBABA 型的回文日期各是哪一天。

题目链接

回文日期https://www.lanqiao.cn/problems/498/learning/

输入描述

输入包含一个八位整数 N,表示日期。

对于所有评测用例,10000101≤N≤89991231,保证 N 是一个合法日期的 8 位数表示。

输出描述

输出两行,每行 1 个八位数。第一行表示下一个回文日期,第二行表示下一个 ABABBABA 型的回文日期。

测试样例

输入样例

20200202

输出样例

20211202
21211212

提交结果截图

详细分析

看题目的第一想法是直接根据输入的日期,来计算下一个回文日期和下一个 ABABBABA 型的回文日期。

但是我想,要是这么计算的话,那考虑日期的合法性就极为复杂了,一不小心就会出错。

所以我想换种方式,先求出所有回文日期,因为有闰年、月份和日期以及回文的限制,回文日期的总数应该不多的(后面我全打印出来了,发现真的不多)。

要找到所有回文日期,就得利用好闰年、月份和日期以及回文的限制

我是这么遍历的:

 for (i = 1; i <= 31; i++)//dd,穷举日期
        for (j = 1; j <= 12; j++)//mm,穷举月份
        {
            if (i > 29 && j == 2)//2月最多29天
                continue;
            else if (i == 31 && (j == 4 || j == 6 || j == 9 || j == 11))//除2月外,4、6、9、11月也不可能有31号
                continue;
            y = (i % 10) * 1000 + (i / 10) * 100 + (j % 10) * 10 + j / 10;//根据日期和月份得到年分
            if (i == 29 && j == 2 && !((y % 4 == 0 && y % 100 != 0) || y % 400 == 0))//若不是闰年
                continue;
            sprintf(buff, "%04d%02d%02d", y, j, i);//通过sprintf将日期存储到buff中
            str.push_back(buff);//将日期存入str中(自动转为string类型)
        }

按照日期,月份、日期月份生成年份(这样必定符合回文)的顺序,这样月份可以根据日期判断是否符合,年份可以根据月日判断是否符合,回文必定符合。

然后就把所有的回文日期都存储到了str中:

vector <string> str;//用来存储所有回文日期

这样生成的回文日期是没有大小顺序的,需要排序方便后面计算:

//放在main函数外
bool cmp(string a, string b)//比较日期大小
{
    return a < b;//日期按从小到大排序
}

//main函数内
 sort(str.begin(), str.end(), cmp);//对所有回文日期做一个从小到大的排序

排完序后打印出来:

01011010 01100110 01111110 01200210 01211210 01300310 01400410 01500510 01600610
01700710 01800810 01900910 02011020 02100120 02111120 02200220 02211220 02300320
02400420 02500520 02600620 02700720 02800820 02900920 03011030 03100130 03111130
03211230 03300330 03400430 03500530 03600630 03700730 03800830 03900930 10011001
10100101 10111101 10200201 10211201 10300301 10400401 10500501 10600601 10700701
10800801 10900901 11011011 11100111 11111111 11200211 11211211 11300311 11400411
11500511 11600611 11700711 11800811 11900911 12011021 12100121 12111121 12200221
12211221 12300321 12400421 12500521 12600621 12700721 12800821 12900921 13011031
13100131 13211231 13300331 13500531 13700731 13800831 20011002 20100102 20111102
20200202 20211202 20300302 20400402 20500502 20600602 20700702 20800802 20900902
21011012 21100112 21111112 21200212 21211212 21300312 21400412 21500512 21600612
21700712 21800812 21900912 22011022 22100122 22111122 22200222 22211222 22300322
22400422 22500522 22600622 22700722 22800822 22900922 30011003 30100103 30111103
30200203 30211203 30300303 30400403 30500503 30600603 30700703 30800803 30900903
31011013 31100113 31111113 31200213 31211213 31300313 31400413 31500513 31600613
31700713 31800813 31900913 32011023 32100123 32111123 32200223 32211223 32300323
32400423 32500523 32600623 32700723 32800823 32900923 40011004 40100104 40111104
40200204 40211204 40300304 40400404 40500504 40600604 40700704 40800804 40900904
41011014 41100114 41111114 41200214 41211214 41300314 41400414 41500514 41600614
41700714 41800814 41900914 42011024 42100124 42111124 42200224 42211224 42300324
42400424 42500524 42600624 42700724 42800824 42900924 50011005 50100105 50111105
50200205 50211205 50300305 50400405 50500505 50600605 50700705 50800805 50900905
51011015 51100115 51111115 51200215 51211215 51300315 51400415 51500515 51600615
51700715 51800815 51900915 52011025 52100125 52111125 52200225 52211225 52300325
52400425 52500525 52600625 52700725 52800825 52900925 60011006 60100106 60111106
60200206 60211206 60300306 60400406 60500506 60600606 60700706 60800806 60900906
61011016 61100116 61111116 61200216 61211216 61300316 61400416 61500516 61600616
61700716 61800816 61900916 62011026 62100126 62111126 62200226 62211226 62300326
62400426 62500526 62600626 62700726 62800826 62900926 70011007 70100107 70111107
70200207 70211207 70300307 70400407 70500507 70600607 70700707 70800807 70900907
71011017 71100117 71111117 71200217 71211217 71300317 71400417 71500517 71600617
71700717 71800817 71900917 72011027 72100127 72111127 72200227 72211227 72300327
72400427 72500527 72600627 72700727 72800827 72900927 80011008 80100108 80111108
80200208 80211208 80300308 80400408 80500508 80600608 80700708 80800808 80900908
81011018 81100118 81111118 81200218 81211218 81300318 81400418 81500518 81600618
81700718 81800818 81900918 82011028 82100128 82111128 82200228 82211228 82300328
82400428 82500528 82600628 82700728 82800828 82900928 90011009 90100109 90111109
90200209 90211209 90300309 90400409 90500509 90600609 90700709 90800809 90900909
91011019 91100119 91111119 91200219 91211219 91300319 91400419 91500519 91600619
91700719 91800819 91900919 92011029 92100129 92111129 92200229 92211229 92300329
92400429 92500529 92600629 92700729 92800829 92900929

看起来也不多是吧?哈哈。

然后要找到“下一个回文日期”,只要找到str中第一个比输入的日期大的回文日期就行了,

而要找到“下一个 ABABBABA 型的回文日期”就是额外增加一个判断条件——回文日期的字符串的第0位和第2位相等,第1位和第3位相等即可:

 for (i = 0; i < str.size(); i++)//寻找“下一个回文日期”
        if (date < str[i])//找到“下一个回文日期”
        {
            cout << str[i] << "\n";//输出“下一个回文日期”
            for (j = i; j < str.size(); j++)//寻找“下一个 ABABBABA 型的回文日期”
                if (str[j][0] == str[j][2] && str[j][1] == str[j][3])//找到“下一个 ABABBABA 型的回文日期”
                {
                    cout << str[j] << "\n";//输出“下一个 ABABBABA 型的回文日期”
                    break;
                }
            break;
        }

带详细注释的源代码

#include <iostream>
#include <cstdio>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
bool cmp(string a, string b)//比较日期大小
{
    return a < b;//日期按从小到大排序
}

int main()
{
    string date;//输入的日期
    int i, j, y;//分别为dd, mm, yyyy
    char buff[9];//用来将日期转换为string类型
    vector <string> str;//用来存储所有回文日期
    for (i = 1; i <= 31; i++)//dd,穷举日期
        for (j = 1; j <= 12; j++)//mm,穷举月份
        {
            if (i > 29 && j == 2)//2月最多29天
                continue;
            else if (i == 31 && (j == 4 || j == 6 || j == 9 || j == 11))//除2月外,4、6、9、11月也不可能有31号
                continue;
            y = (i % 10) * 1000 + (i / 10) * 100 + (j % 10) * 10 + j / 10;//根据日期和月份得到年分
            if (i == 29 && j == 2 && !((y % 4 == 0 && y % 100 != 0) || y % 400 == 0))//若不是闰年
                continue;
            sprintf(buff, "%04d%02d%02d", y, j, i);//通过sprintf将日期存储到buff中
            str.push_back(buff);//将日期存入str中(自动转为string类型)
        }
    sort(str.begin(), str.end(), cmp);//对所有回文日期做一个从小到大的排序
    /*for (i = 0; i < str.size(); i++)
        cout << str[i] << "\n";*/
    cin >> date;
    for (i = 0; i < str.size(); i++)//寻找“下一个回文日期”
        if (date < str[i])//找到“下一个回文日期”
        {
            cout << str[i] << "\n";//输出“下一个回文日期”
            for (j = i; j < str.size(); j++)//寻找“下一个 ABABBABA 型的回文日期”
                if (str[j][0] == str[j][2] && str[j][1] == str[j][3])//找到“下一个 ABABBABA 型的回文日期”
                {
                    cout << str[j] << "\n";//输出“下一个 ABABBABA 型的回文日期”
                    break;
                }
            break;
        }
    return 0;
}

  • 15
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值