蓝桥杯真题:回文数字

文章介绍了如何解决蓝桥杯竞赛中关于回文日期的编程题目。作者首先解释了回文日期的概念,然后分享了两种解题思路:从年份开始模拟,寻找ABAB型日期,以及优化方法,检查样例年份是否包含回文日期。代码被逐步修改以适应不同情况,特别是处理样例年份之后的回文日期。
摘要由CSDN通过智能技术生成

蓝桥杯真题:回文数字 https://www.lanqiao.cn/problems/498/learning/

解题思路:

首先看怎么得到一个回文日期——

我们随便打四个数字2252,如果要得到一个回文数字需要什么?

一个对称轴,像一个镜子一样,然后对称过去:2252 | 2522

所以我们可以从样例的年份开始模拟,2020 | 0202,判断是否为回文数字,判断是不是ABAB型。

不符合就年份加一,2021 | 1202,直到得到我们想要的结果。


原本也是没有什么思路,但是模拟了一下人类思考的过程,是从年份开始模拟,然后回文对称过去,看得到的月份和日期是否合法。输出第一个合法的日期(最小),每次合法判断日期是否月和日是否相等(ABAB型)

只输出第一次合法日期的方法引入一个变量t,当出现回文数字后加一,所以当变量t为0的时候,就是回文日期第一次出现的时候。

于是就有了接下来这个程序:

#include <iostream>
#include <cstdio>
using namespace std;
int month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};    //设定每个月的天数用于判断天数是否合法
int n, m, d;
int judge(int y) {
    if((y % 100 != 0 && y % 4 == 0) || y % 400 == 0) return 29;    //单独判断二月的天数
    else return 28;
}
void out(int y, int m, int d) {    //将日期完全输出
    cout << y;
    if(m < 10) cout << "0";
    cout << m;
    if(d < 10) cout << "0";
    cout << d << endl;
}
bool check(int y, int m, int d) {    //检查日期是否合法
    if((m > 12 || m == 0) || d == 0) return false;    //检查月是否合法(在1-12月内)
    if((m == 2 && d <= judge(y)) || ((m != 2) && d <= month[m - 1]))    //检查日是否合法(在1-当月天数内)
        return true;
    else return false;
}
int main() {
    cin >> n;
    int y = n / 10000, t = 0;        //从当前年份开始,依次向后
    for(int i = y + 1; i; i ++) {
        m = i % 10 * 10 + (i % 100) / 10;        //计算年份对应的月份和日期
        d = i / 1000 + ((i % 1000) / 100) * 10;
        if(check(i, m, d)) {        //如果日期合法,就进行输出。
            if(t == 0) out(i, m, d);    //非ABAB型只用输出第一次的,之后的再判断是否为ABAB型。
            if(m == d) {                //当属于ABAB型之后,进行输出。
                out(i, m, d);
                break;
            }
        }
        y ++; t ++;
    }
    return 0;
}

但进行提交之后,只对了两个样例。

于是我开始试各种数字,再这里发现了纰漏:

当输入样例非回文数,但该年份存在回文数时,例如:20200201,第二天20200202就是回文数,但我们的程序是从第二年开始的,所以遇见这种样例就会出错。那么这时就需要改进。


所以现在怎么改进呢?难道说从样例的日期开始向后枚举吗?那也太麻烦了,其实我们知道,这种情况是当前年份存在回文日期,所以我们只要判断样例的年份是否是包含回文日期的年份,然后判断当年回文日期的年份是不是在样例的日期之后就可以了。

代码如下:

#include <iostream>
#include <cstdio>
using namespace std;
int month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int n, m, d;
int judge(int y) {
    if((y % 100 != 0 && y % 4 == 0) || y % 400 == 0) return 29;
    else return 28;
}
void out(int y, int m, int d) {
    cout << y;
    if(m < 10) cout << "0";
    cout << m;
    if(d < 10) cout << "0";
    cout << d << endl;
}
bool check(int y, int m, int d) {
    if((m > 12 || m == 0) || d == 0) return false;
    if((m == 2 && d <= judge(y)) || ((m != 2) && d <= month[m - 1]))
        return true;
    else return false;
}
int main() {
    cin >> n;
    int y = n / 10000, t = 0;
    m = y % 10 * 10 + (y % 100) / 10;
    d = y / 1000 + ((y % 1000) / 100) * 10;
///
            //新增部分
    int m1 = n % 10000 / 100;    //计算样例的月份
    int d1 = n % 100;            //计算样例的日期
    if(check(y, m, d) && (m > m1 || d > d1)) {    //当前年份包含回文日期,并且该日期在样例之后
        out(y, m, d);    //输出该日期
        if(m == d) {        //若该日期刚好为回文数字则输出两次并直接结束程序
          out(y, m, d);
          return 0;
        }
        t ++;            //如若此时没有结束程序,则表示样例年份的回文日期并非ABAB型,
    }                    //那么就是第一个最小的回文数字,需要用变量标记防止第二个非ABAB型的回文数字输出
//
    for(int i = y + 1; i; i ++) {
        m = i % 10 * 10 + (i % 100) / 10;
        d = i / 1000 + ((i % 1000) / 100) * 10;
        if(check(i, m, d)) {
            if(t == 0) out(i, m, d);
            if(m == d) {
                out(i, m, d);
                break;
            }
            t ++;
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值