跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++算法

模拟算法实战:铺地毯、回文日期与扫雷题解

模拟算法通过枚举所有可能性来解决问题,核心在于优化枚举策略。通过铺地毯、回文日期、扫雷三道经典题展示了不同场景下的应用。铺地毯利用逆序枚举提前终止;回文日期通过固定月日反推年份降低复杂度;扫雷则利用状态传递进行逻辑推导。掌握这些技巧能有效提升处理此类问题的效率。

MqEngine发布于 2026/3/14更新于 2026/10/2692 浏览
模拟算法实战:铺地毯、回文日期与扫雷题解

模拟算法概述

枚举是模拟算法的核心,本质就是把所有可能的情况罗列出来,筛选出符合题意的那一个。虽然暴力枚举容易超时,但在数据范围允许的情况下,它是最直接的解法。如果直接枚举会超时,就需要结合题目特性优化枚举顺序或对象(比如二分、双指针等)。思考重点在于:枚举什么?按什么顺序?怎么枚举?

经典例题解析

1. 铺地毯

问题描述:给定 n 张地毯的坐标和长宽,查询某个点被哪张最后铺设的地毯覆盖。

思路: 我们需要找到覆盖该点的最后一张地毯。如果正序遍历,必须检查完所有地毯才能确定结果;如果逆序遍历,一旦找到第一张覆盖的点,就是答案,可以直接返回。这种优化能显著减少不必要的判断。

代码实现:

#include <iostream>
using namespace std;

typedef long long LL;
const int N = 1e5 + 10;
LL a[N], b[N], g[N], k[N]; // x, y, width, height
int n;

int find(int x, int y) {
    for (int i = n; i >= 1; i--) {
        if (x >= a[i] && y >= b[i] && x <= a[i] + g[i] && y <= b[i] + k[i]) {
            return i;
        }
    }
    return -1;
}

int main() {
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i] >> b[i] >> g[i] >> k[i];
    LL x, y;
    cin >> x >> y;
    cout << find(x, y) << endl;
    return 0;
}

2. 回文日期

问题描述:在给定日期范围内,统计有多少个日期是回文的。

思路: 回文日期的特点是年份由月日决定,或者月日由年份决定。 策略一:枚举月日组合,反推年份。复杂度 O(12*31),效率最高。注意闰年 2 月只有 29 天。 策略二:枚举年份,反推月日。复杂度 O(年份差),稍慢但逻辑直观。

代码实现(枚举月日):

#include <iostream>
using namespace std;

int m[13] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

int main() {
    int begin, end;
    cin >> begin >> end;
    int ret = 0;
    for (int i = 1; i <= 12; i++) {
        for (int j = 1; j <= m[i]; j++) {
            // 构造回文年份部分
            int k = j % 10 * 1000 + j / 10 * 100 + i % 10 * 10 + i / 10;
            int num = k * 10000 + i * 100 + j;
            if (num >= begin && num <= end) ret++;
        }
    }
    cout << ret << endl;
    return 0;
}

代码实现(枚举年份):

#include <iostream>
using namespace std;

bool check_year(int y) {
    return (y % 4 == 0 && y % 100 != 0) || (y % 400 == 0);
}

int reverse_num(int x) {
    int k = 0;
    while (x) {
        k = k * 10 + x % 10;
        x /= 10;
    }
    return k;
}

int main() {
    int begin, end;
    cin >> begin >> end;
    int x = begin / 10000;
    int y = end / 10000;
    int ret = 0;
    for (int i = x; i <= y; i++) {
        int k = reverse_num(i);
        int month = k / 100;
        int day = k % 100;
        bool flag = false;
        if (month > 0 && month <= 12) {
            if (month == 2) {
                flag = check_year(i) ? (day <= 29) : (day <= 28);
            } else if (month == 4 || month == 6 || month == 9 || month == 11) {
                flag = day <= 30;
            } else {
                flag = day <= 31;
            }
        }
        if (flag) {
            int palindrome_date = i * 10000 + month * 100 + day;
            if (palindrome_date >= begin && palindrome_date <= end) ret++;
        }
    }
    cout << ret << endl;
    return 0;
}

3. 扫雷

问题描述:已知第二列的数字,推断第一列是否有雷。

思路: 这是一个状态推导问题。第一列的状态决定了后续行的状态。由于第一行第一列要么有雷要么没雷,只有两种可能。我们可以分别假设第一格有雷和无雷,然后依次推导后续格子是否合法。 注意边界条件:需要多判断一行(n+1),确保推导出的第 n+1 个格子没有雷,逻辑才闭环。

代码实现:

#include <iostream>
using namespace std;

const int N = 1e4 + 10;
int a[N], b[N]; // a: 第一列,b: 第二列

int check1(int n) {
    a[1] = 0; // 假设第一格无雷
    for (int i = 2; i <= n + 1; i++) {
        a[i] = b[i - 1] - a[i - 1] - a[i - 2];
        if (a[i] < 0 || a[i] > 1) return 0;
    }
    return a[n + 1] == 0 ? 1 : 0;
}

int check2(int n) {
    a[1] = 1; // 假设第一格有雷
    for (int i = 2; i <= n + 1; i++) {
        a[i] = b[i - 1] - a[i - 1] - a[i - 2];
        if (a[i] < 0 || a[i] > 1) return 0;
    }
    return a[n + 1] == 0 ? 1 : 0;
}

int main() {
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> b[i];
    int ret = 0;
    ret += check1(n);
    ret += check2(n);
    cout << ret << endl;
    return 0;
}

目录

  1. 模拟算法概述
  2. 经典例题解析
  3. 1. 铺地毯
  4. 2. 回文日期
  5. 3. 扫雷

更多推荐文章

查看全部
  • 如何入门网络安全技术与伦理规范
  • Spring Boot 微服务架构设计与实现
  • Protege 构建知识图谱并接入 Neo4j 与前端可视化实战
  • Android Framework 开发:技术深度、核心模块与职业前景
  • Trae IDE 安装与使用指南:AI 原生开发环境详解
  • AI 大模型通信机制:流式传输与数据封装逻辑解析
  • Python 安装与环境配置详细教程
  • 基于 Ollama 本地部署 Llama3 模型指南
  • PHP 调用 DeepSeek API 接口示例
  • 开源智能家居平台指南:构建自主可控的智能生活系统
  • ASP.NET Core 主机模型详解:Host、WebHost 与 WebApplication 对比与实践
  • 错误定位 Prompt:利用大模型快速解析异常堆栈
  • Linux 系统监控工具 top 命令详解与实战
  • Git 结构原理与分支管理模型实战分析
  • 基于 Java+SpringBoot+UniApp 的待办事项提醒微信小程序设计与实现
  • Linux 内核设计的核心思想与架构原则
  • 解决 Edge 边栏 Copilot 图标消失的问题
  • Edge 边栏 Copilot 图标消失修复方案
  • 自然语言处理(NLP)高级应用与前沿技术实战
  • 二分查找与二分答案详解

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online