2023年海淀区中小学信息学竞赛复赛(小学组试题第二题 回文时间 (time))

一、先看原题:


二、读懂题目:

时间格式是 HH:MM,我们要找下一个 回文时间 (形如 ab:ba,即小时的两个数字倒过来就是分钟的两个数字)。

所以:把小时的十位和个位互换成分钟,若分钟合法(0..59)且时间在给定时间之后,则就是一个候选答案。从现在起顺时针往后看每个小时(最多看 24 个小时),第一个满足条件的就是答案。


三、关键点:

  • 回文时间定义是 HH:MM 形式且 MM 等于把 HH 的两位数倒过来(比如 1331,对应时间 13:31)。

  • 在 24 小时制下,只要 MM < 60 才合法。把 00~23 的小时翻转后,合法的小时有:
    00,01,02,03,04,05,10,11,12,13,14,15,20,21,22,23

    对应的回文时间为:

    00:00, 01:10, 02:20, 03:30, 04:40, 05:50, 10:01, 11:11, 12:21, 13:31, 14:41, 15:51, 20:02, 21:12, 22:22, 23:32

  • 处理步骤:读入当前时间(HH:MM),把它转换为"从午夜起的分钟数";把数组中每个回文时间也转换为分钟数;找到第一个严格大于当前分钟数的回文时间并输出;如果找不到(当天都没有更晚的回文时间),输出 00:00(即第二天的第一个回文时间)。


四、参考程序1:(预设比较法)

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

// 把 "HH:MM" 转换成 从午夜起的分钟数(0..1439)
int timeToMinutes(const string &t) {
    int hh = stoi(t.substr(0,2));
    int mm = stoi(t.substr(3,2));
    return hh * 60 + mm;
}

int main() {
    string cur;
    cin >> cur;     // 读取 "HH:MM"

    // 预先列出一天内按时间顺序的所有回文时间
    vector<string> pal = {
        "01:10","02:20","03:30","04:40","05:50",
        "10:01","11:11","12:21","13:31","14:41","15:51",
        "20:02","21:12","22:22","23:32"
    };

    int now = timeToMinutes(cur);

    // 找第一个严格在当前时间之后的回文时间
    for (const string &p : pal) {
        if (timeToMinutes(p) > now) {
            cout << p << '\n';
            return 0;
        }
    }

    // 当天没有则输出第二天最早的回文时间(即 00:00)
    cout << "00:00\n";
    return 0;
}

五、程序1的说明:

  • 把回文时间写出来放好 (就像把你喜欢的卡片排好队)

    我们把这 15 个回文时间排在 pal 向量里,顺序是从 01:1023:32,就像一日时间的顺序。

  • 把输入时间转换成"分钟" (把时间换算成一个数字,方便比较)

    例如 13:3113*60 + 31 = 811 分钟。

  • 逐个去数组里比较

    • pal[0]00:00)对应的分钟数是不是 > 当前分钟数?如果是,就输出它;

    • 否则继续看 pal[1],依次往后;

    • 如果数组走完了都没有找到(说明今天剩下的时间里没有更晚的回文时间),就输出 00:00(第二天的第一个回文时间)。

  • 为什么不包含当前时刻?

    题目要求"在此之后(不包含此刻)",所以如果输入本身就是回文时间(比如输入 13:31),程序不会输出 13:31,而是会输出下一次的回文时间(这里是 14:41,因为在数组里 13:31 后面就是 14:41


六、参考程序2:(模拟翻转法)

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

// 把一个两位数左右翻转,例如 23 -> 32
int flip(int x) {
    int a = x / 10;
    int b = x % 10;
    return b * 10 + a;
}

int main() {
    string s;
    cin >> s;               // 输入格式 "HH:MM"

    int H = stoi(s.substr(0, 2));
    int M = stoi(s.substr(3, 2));

    for (int h = H; h <= 23; h++) {
        int m = flip(h);    // 翻转小时得到分钟
        if (m < 60) {       // 分钟必须合法
            if (h > H || m > M) { // 必须是当前时间之后
                printf("%02d:%02d\n", h, m);
                return 0;
            }
        }
    }

    // 如果一天中没找到,下一天的第一个回文时间一定是 00:00
    cout << "00:00\n";
    return 0;
}

七、程序2的说明:

1、书写翻转函数:

cpp 复制代码
// 把一个两位数左右翻转,例如 23 -> 32
int flip(int x) {
    int a = x / 10;
    int b = x % 10;
    return b * 10 + a;
}
  • flip ()把小时的两个数字互换顺序。

  • 示例:

    • flip(23)a=2, b=3 → 返回 32

    • flip(5)a=0, b=5 → 返回 50(表示 05 小时对应分钟 50,时间 05:50)。

  • 想像把小时放到镜子里,镜子里的数字就是函数返回的结果。


2、转换字符串为 整型:

cpp 复制代码
    int H = stoi(s.substr(0, 2));
    int M = stoi(s.substr(3, 2));
  • 把输入字符串拆开:

    • s.substr(0,2) 取前两位(小时的两位,例如 "12"),用 stoi 变成整数 12,放到 H

    • s.substr(3,2) 取后两位(分钟 "21"),变成整数 21,放到 M

  • 假如输入 "05:07",则 H=5M=7

> 小提醒:这个写法要求输入必须是 HH:MM 的格式(两位小时,两位分钟,中间有冒号)。题目保证了这一点。


3、程序的核心逻辑:

cpp 复制代码
    for (int h = H; h <= 23; h++) {
        int m = flip(h);    // 翻转小时得到分钟
        if (m < 60) {       // 分钟必须合法
            if (h > H || m > M) { // 必须是当前时间之后
                printf("%02d:%02d\n", h, m);
                return 0;
            }
        }
    }

(1)for (int h = H; h <= 23; h++)

  • 从当前小时 H 开始,检查 H, H+1, H+2, ... 一直到 23(当天最后一小时)。

  • 我们只检查当天剩下的小时,因为如果当天找不到再处理第二天的 00:00


(2)int m = flip(h);

把小时 h 翻转,得到相应的"回文分钟" m。例如 h=13m=31


(3)if (m < 60)

分钟必须是合法的分钟(0 到 59)。有些小时翻转后会得到 6171 等不合法的分钟,就要跳过(例如 1661 不合法)。


(4)if (h > H || m > M)

  • 这句是确保严格在当前时间之后

    • 如果 h > H,说明我们检查的是比当前小时更晚的小时(比如当前 H=12,现在 h=13),那么任何合法的 m 都在之后,可以直接接受。

    • 如果 h == H(第一圈),则需要 m > M,保证分钟比当前分钟晚(因为题目不包含当前刻)。

  • 这样就能保证找到的时间是"下一次"回文时间,不会返回当前时刻本身。


(5)printf("%02d:%02d\n", h, m);

找到后用 printf 输出,例如 05:50%02d 确保两位显示,不足补 05 会显示为 05


(6)return 0;

找到答案就结束程序,不继续循环。


4、如果循环结束没找到,就输出 "00:00":

cpp 复制代码
    // 如果一天中没找到,下一天的第一个回文时间一定是 00:00
    cout << "00:00\n";
    return 0;
}

八、总结:

1、预设比较法:

把"小时"照镜子变成分钟:

  • ab:ba 是回文时间;

  • 有效小时(翻转后分钟 < 60)只有这些:00,01,02,03,04,05,10,11,12,13,14,15,20,21,22,23

    记住这 16 个就够用了!


2、模拟反转法:

  • 把小时照镜子得到分钟(flip)。

  • 如果镜像分钟合法(<60)并且时间比现在晚(严格大于),那就是答案。

  • 从当前小时往后一小时一小时地试,试到 23 还没找到就输出 00:00

相关推荐
Data_agent9 小时前
1688按图搜索1688商品(拍立淘)API ,Python请求示例
爬虫·python·算法·图搜索算法
代码雕刻家9 小时前
1.9.课设实验-数据结构-图-校园跑最短路径
c语言·数据结构·算法·图论
white-persist9 小时前
【攻防世界】reverse | re1-100 详细题解 WP
c语言·开发语言·网络·汇编·python·算法·网络安全
.YM.Z10 小时前
【数据结构】:排序(二)——归并与计数排序详解
数据结构·算法·排序
武帝为此10 小时前
【数据结构之树状数组】
数据结构·算法
失败才是人生常态10 小时前
算法题归类学习
学习·算法
还没想好取啥名10 小时前
C++11新特性(一)——原始字面量
开发语言·c++
天赐学c语言10 小时前
12.6 - K个一组翻转链表 && C 编译到执行的4个阶段
数据结构·c++·链表·c编译
leoufung10 小时前
用 DFS 拓扑排序吃透 LeetCode 210:Course Schedule II
算法·leetcode·深度优先