【蓝桥杯】 C++ 回文日期

文章描述了一个编程问题,要求计算给定日期后的下一个回文日期和ABABBABA型日期。解决方案通过循环遍历年份和调整日期来找到符合条件的日期,并确保日期的合法性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

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

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

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

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

输入描述

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

输出描述

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

实现代码

#include<bits/stdc++.h>
using namespace std;

int month[]={0,31,28,31,30,31,30,31,31,30,31,30,31};

int main()
{
    // 给 yyyymmdd,找出下一个ABCDDCBA型,下一个ABABBABA型
    int yy,mm,dd;

    // char input[8]={0};
    // for(int i=0;i<8;i++)
    // {
    //     cin>>input[i];
    // }
    // sscanf(input,"%4d %2d %2d",&yy,&mm,&dd); // 注意后面的 & 符号
    scanf("%4d %2d %2d",&yy,&mm,&dd); // 这个直接把输入放到想要的地方里
    //cout<<yy<<"-"<<mm<<"-"<<dd<<endl;
    
    int next_ABCD_yy,next_ABCD_mm,next_ABCD_dd; // 下一个ABCDDCBA回文
    for(int i=yy;;i++)
    {
        next_ABCD_yy=i; 
        next_ABCD_mm=next_ABCD_yy%10*10 + next_ABCD_yy/10%10; //倒数第一位*10+倒数第二位 2021取12 2149 9412
        next_ABCD_dd=next_ABCD_yy/100%10*10 +next_ABCD_yy/1000; //倒数第三位*10+倒数第四位 2021取02
        
        // 比如 21210101 ,下一次ABAB型应该是21211212,但是年加一以后就很远
        if(next_ABCD_yy==yy&&next_ABCD_mm==mm&&next_ABCD_dd==dd)
        {
            continue;
        }

        // 如果月份大于12或者小于1 或者 日期大于本月最大日子或者小于1,就继续
        if(next_ABCD_mm>12||next_ABCD_mm<1||next_ABCD_dd<1||next_ABCD_dd>month[next_ABCD_mm])
        {
            continue;
        }
        cout<<next_ABCD_yy;
        cout<<setw(2)<<setfill('0')<<next_ABCD_mm;
        cout<<setw(2)<<setfill('0')<<next_ABCD_dd<<endl;
        break;
    }

    int next_ABAB_yy,next_ABAB_mm,next_ABAB_dd; // 下一个ABAB BABA回文
    for(int i=yy;;i++)
    {
        next_ABAB_yy=i; 
        next_ABAB_mm=next_ABAB_yy%10*10 + next_ABAB_yy/10%10; //倒数第一位*10+倒数第二位 2021取12 2149 9412
        next_ABAB_dd=next_ABAB_yy/100%10*10 +next_ABAB_yy/1000; //倒数第三位*10+倒数第四位 2021取02
        
        // 如果 ABCD 反过来,DC不等于BA,那么证明AB不等于CD,不满足ABAB 
        // 比如 2021 反过来 12 和 02不等,证明 2021不是ABAB型
        if(next_ABAB_dd!=next_ABAB_mm) 
        {
            continue;
        }
       
        // 比如 21210101 ,下一次ABAB型应该是21211212,但是年加一以后就很远
        if(next_ABAB_yy==yy&&next_ABAB_mm==mm&&next_ABAB_dd==dd)
        {
            continue;
        }
        
        // 如果月份大于12或者小于1 或者 日期大于本月最大日子或者小于1,就继续
        if(next_ABAB_mm>12||next_ABAB_mm<1||next_ABCD_dd<1||next_ABCD_dd>month[next_ABAB_mm])
        {
            continue;
        }

        cout<<next_ABAB_yy;
        cout<<setw(2)<<setfill('0')<<next_ABAB_mm;
        cout<<setw(2)<<setfill('0')<<next_ABAB_dd<<endl;
        break;
    }
}

解题思路

只要碰到有年月日的题,首先把每个月的天数存到数组里后面备用。然后把输入的东西分别存到年月日里面,方便后面操作。

先找第一个 ABCDDCBA 回文,直接放循环里面,把需要比较的位通过算数存起来,后面比一下就行,还需要对每月的天数进行限制,然后输出,注意输出的时候需要保持格式一致。

下一个 ABABBABA 回文和这个类似,需要注意的是 for 循环的条件,定义从输入的这一年开始,如果从下一年开始,如果输入21210101,类似 21211212 这样的就会被略去,从 2122 年开始找,所以需要加一个判断,如果输入的这个就是 ABABBABA 型的,就找下一个,不会出现因为在同一年就被忽略的情况。

注意点

  • 首先注意固定格式输出,在前面说过,cout<<setw(2)<<setfill('0')<<next_ABAB_dd<<endl; 这样就可以输出想要的位数,如果有空位填充字符是什么。
  • 其次注意 for 循环不要从下一年开始,因为本年可能会出现答案,所以要加一点判断。

知识点

  • 输出固定位数:cout<<setw(2)<<setfill('0')<<next_ABAB_dd<<endl;
  • 函数 sscanfscanf ,注意不同之处。出现年月日这一类,就存到设好的变量里面。有两种把输入的东西存进给定变量的方法。
	// 1
    char input[8]={0};
    for(int i=0;i<8;i++)
    {
        cin>>input[i];
    }
    sscanf(input,"%4d %2d %2d",&yy,&mm,&dd); // 注意后面的 & 符号
    // 2
    scanf("%4d %2d %2d",&yy,&mm,&dd); // 这个直接把输入放到想要的地方里
### 蓝桥杯 回文日期 算法 实现 #### 问题分析 蓝桥杯中的回文日期问题是关于查找特定形式的回文日期的任务。具体来说,需要在一个给定日期之后找到下一个满足条件的回文日期以及特殊类型的回文日期(如 `ABABBABA` 形式的日期)。这类问题通常涉及日期处理、字符串操作和算法设计。 以下是基于 C/C++ 的解决方案及其核心逻辑: --- #### 解决方案概述 为了高效解决问题,可以采用如下策略: 1. **日期合法性验证**:确保生成的日期是合法的日历日期。 2. **回文检测**:判断一个八位数是否为回文。 3. **ABABBABA 类型检测**:进一步确认日期是否符合此模式。 4. **循环遍历**:从输入日期开始逐日递增,直到找到符合条件的目标日期为止。 --- #### 核心代码实现 (C++) 以下是一个完整的 C++ 实现示例: ```cpp #include <iostream> #include <string> using namespace std; // 判断日期是否有效 bool isValidDate(int year, int month, int day) { if (month < 1 || month > 12) return false; int daysInMonth[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) { daysInMonth[2] = 29; // 处理闰年情况 } if (day < 1 || day > daysInMonth[month]) return false; return true; } // 将日期转换为八位字符串 string dateToString(int y, int m, int d) { string s = ""; s += to_string(y); if (m < 10) s += '0'; s += to_string(m); if (d < 10) s += '0'; s += to_string(d); return s; } // 检查是否为回文串 bool isPalindrome(string str) { int n = str.length(); for (int i = 0; i < n / 2; ++i) { if (str[i] != str[n - 1 - i]) return false; } return true; } // 检查是否为 ABABBABA 型 bool isSpecialPattern(string str) { if (str[0] == str[1] && str[2] == str[5] && str[3] == str[4] && str[6] == str[7] && str[2] == str[6]) return true; return false; } // 主函数 void findNextPalindromicDates() { int N_year, N_month, N_day; cin >> N_year >> N_month >> N_day; while (true) { N_day++; if (N_month == 2 && N_day > 29 || (N_month == 4 || N_month == 6 || N_month == 9 || N_month == 11) && N_day > 30 || N_day > 31) { N_day = 1; N_month++; } if (N_month > 12) { N_month = 1; N_year++; } string currentDateStr = dateToString(N_year, N_month, N_day); if (!isValidDate(N_year, N_month, N_day)) continue; bool foundPlaindrome = isPalindrome(currentDateStr); // 是否为普通回文 bool foundSpecial = isSpecialPattern(currentDateStr); // 是否为 ABABBABA 型 if (foundPlaindrome || foundSpecial) { cout << "Next Palindrome Date: " << currentDateStr << endl; break; } } } int main() { findNextPalindromicDates(); return 0; } ``` --- #### 功能说明 上述程序实现了以下几个功能模块: 1. **日期有效性校验**:通过数组存储每个月的最大天数,并考虑闰年的特殊情况[^1]。 2. **回文检测**:利用双指针技术逐一比较字符对称性[^2]。 3. **ABABBABA 特殊模式匹配**:按照题目定义的规则进行逐项对比[^3]。 4. **日期递增机制**:模拟手动增加日期的过程,同时保持月份和年份的一致性[^4]。 --- #### 输出样例 假设输入日期为 `20210202`,则可能输出如下结果: ``` Next Palindrome Date: 20211202 ``` 如果目标是寻找 `ABABBABA` 类型,则可能会返回更远的一个日期,例如 `11111111` 或其他符合条件的结果。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值