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

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

模拟算法核心在于枚举所有可能情况。本文通过铺地毯、回文日期、扫雷三道题,展示枚举策略的优化技巧。铺地毯采用逆序枚举快速定位;回文日期通过固定月日或年份减少计算量;扫雷利用第一列状态推导后续行。合理选择枚举对象能大幅提升效率。

WenxuanMa发布于 2026/3/16更新于 2026/6/1016 浏览
模拟算法实战:铺地毯、回文日期与扫雷详解

前言

模拟算法的核心思想是枚举,即把所有可能的情况都罗列出来,从中找出符合题目要求的那一个。虽然这是一种暴力方法,容易超时,但在数据范围允许的情况下,它是最直接的解法。

使用枚举策略时,重点思考三个问题:枚举的对象是什么?枚举的顺序如何(正序还是逆序)?以及枚举的方式(普通循环、递归还是二进制)。

一、铺地毯

题目描述 给定 n 张地毯,每张地毯由左下角坐标 (x, y) 和长宽 g, k 定义。查询某个位置 (X, Y) 被哪一张地毯覆盖。如果有多个,输出最后放置的那一张。

思路解析 我们需要找到覆盖 (X, Y) 的地毯中编号最大的那个。如果从前往后枚举,必须遍历完所有地毯才能确定结果。更优的做法是逆序枚举:从最后一张地毯开始往前找,第一次遇到覆盖该位置的地毯,就是答案。

代码实现

#include<iostream>
using namespace std;
typedef long long LL;
const int N = 1e5 + 10;
LL a[N], b[N], g[N], k[N];
int n;

int find_pos(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_pos(x, y) << endl;
    return 0;
}

二、回文日期

题目描述 给定两个日期 begin 和 end,统计区间内有多少个回文日期。

思路解析 回文日期具有对称性。对于固定的年份,只有特定的月日组合能构成回文;反之亦然。这里提供两种枚举策略:

  1. 枚举月 + 日:复杂度约 10^3。根据月日反推年份,检查是否在区间内且合法。注意 2 月 29 日的闰年判断。
  2. 枚举年:复杂度约 10^4。根据年份反推月日,校验合法性。

策略一通常更快,因为月份和日期的组合远少于年份的组合。

代码实现:枚举月 + 日

#include<iostream>
using namespace std;
// 每月天数表,2 月设为 29 天方便处理闰年逻辑
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(check_year(i) && month == 2) flag = (day <= 29);
            else if((month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) && day <= 31) flag = true;
            else if(month == 2) flag = (day <= 28);
            else if(month == 4 || month == 6 || month == 9 || month == 11) flag = (day <= 30);
            
            if(flag){
                int palindrome_date = k + i * 10000;
                if(palindrome_date >= begin && palindrome_date <= end) ret++;
            }
        }
    }
    cout << ret << endl;
    return 0;
}

三、扫雷

题目描述 已知第二列每个格子周围的雷数,推断第一列是否有雷。

思路解析 这是一个典型的递推问题。一旦确定了第一列第一个格子的状态(有雷或无雷),后续行的状态就被第二列的数据唯一确定了。

我们只需要枚举第一列第一个格子的两种情况:有雷(1)和无雷(0)。然后依次推导后续行,看是否能满足所有约束条件。

注意点

  1. 递推公式:第二列第 i 个格子的雷数等于第一列第 i-1, i, i+1 个格子的雷数之和。因此可以反推第一列的状态。
  2. 边界检查:需要额外检查推导出的第 n+1 个格子是否为 0,确保逻辑闭环。

代码实现

#include<iostream>
using namespace std;
const int N = 1e4 + 10;
int a[N], b[N];

// 假设第一格没有雷
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;
    }
    if(a[n + 1]) return 0;
    return 1;
}

// 假设第一格有雷
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;
    }
    if(a[n + 1]) return 0;
    return 1;
}

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. 二、回文日期
  4. 三、扫雷
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • 使用 Higress MCP Server 插件将 REST API 转为 AI 工具
  • Stable Diffusion v1.5 Archive 与 SDXL-Lightning 生成速度与质量对比
  • Stable Diffusion 提示词编写与 ControlNet 控制网实战指南
  • KingbaseES 兼容模式下 SQL Server 开发技巧与常见坑点
  • Linux 基础 IO:从一切皆文件到自定义 libc 缓冲区
  • OpenCode AI 编程工具使用教程:从安装到实战
  • Cloudflare AI Gateway 接入 Google Gemini 指南
  • Transformer 论文解读:前馈神经网络(FFN)详解
  • 降低论文 AI 检测率的 10 条指令与工具实测
  • Jetson Orin NX 搭载 Fast-LIO2 的自主无人机系统部署实战
  • 网络安全面试常见问题与解答指南
  • Visual C++ 运行库缺失问题快速解决指南
  • 飞书机器人搭建指南:基于 Webhook 实现高效消息推送
  • 零成本搭建飞书机器人:利用 Webhook 实现高效消息推送
  • Python AI 大模型部署指南:本地运行、API 服务与 Docker 封装
  • RexUniNLU 前端联动:Vue 组件封装 + Schema 可视化编辑器
  • 远程批量管理 NAS 设备,Ansible 让操作自动化
  • 链表详解及C++实现
  • Python 搭建具备记忆与人工干预功能的搜索机器人
  • 网格搜索参数优化的 XGBoost+SHAP 回归预测及可视化分析

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如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