查看: 26|回复: 0

蓝桥杯2022省赛B组扫雷问题:BFS算法实战解析

[复制链接]
  • TA的每日心情
    擦汗
    10 小时前
  • 签到天数: 37 天

    [LV.5]常住居民I

    36

    主题

    0

    回帖

    67

    积分

    注册会员

    Rank: 2

    积分
    67
    发表于 2025-7-2 10:41:17 | 显示全部楼层 |阅读模式
    一、问题背景
    题目模拟了扫雷游戏的场景:给定n个炸雷的位置和爆炸半径,以及m个排雷火箭的位置和引爆半径。当一个炸雷被引爆后,会引爆在其爆炸范围内的其他未引爆炸雷,要求计算最终被引爆的炸雷总数。
    二、核心算法思路
    • BFS广度优先搜索:模拟连锁引爆过程
    • 空间优化存储:使用嵌套unordered_map存储炸雷位置
    • 距离优化计算:使用距离平方避免浮点运算

    三、完整代码解析(带注释)
    1. #include <iostream>
    2. #include <vector>
    3. #include <queue>
    4. #include <cmath>
    5. #include <unordered_map>
    6. using namespace std;

    7. // 定义炸雷/火箭结构体
    8. struct Point {
    9.     int x, y, r;        // 坐标和爆炸半径
    10.     bool exploded = false; // 是否已被引爆
    11. };

    12. // 计算两点间距离平方(避免开方运算)
    13. int distance2(int x1, int y1, int x2, int y2) {
    14.     int dx = x1 - x2;
    15.     int dy = y1 - y2;
    16.     return dx*dx + dy*dy;
    17. }

    18. int main() {
    19.     ios::sync_with_stdio(false);  // 关闭同步提升IO速度
    20.     cin.tie(nullptr);
    21.    
    22.     int n, m;  // n-炸雷数量 m-火箭数量
    23.     cin >> n >> m;
    24.    
    25.     // 使用双层哈希表存储炸雷(x→y→炸雷列表)
    26.     unordered_map<int, unordered_map<int, vector<Point>>> mines;
    27.     vector<Point> mine_list;  // 炸雷列表备份
    28.    
    29.     // 读取炸雷数据
    30.     for (int i = 0; i < n; ++i) {
    31.         int x, y, r;
    32.         cin >> x >> y >> r;
    33.         mine_list.push_back({x, y, r, false});
    34.         mines[x][y].push_back({x, y, r, false});
    35.     }
    36.    
    37.     queue<Point> q;  // BFS队列
    38.     int count = 0;   // 引爆计数器
    39.    
    40.     // 处理排雷火箭(初始引爆点)
    41.     for (int i = 0; i < m; ++i) {
    42.         int x, y, r;
    43.         cin >> x >> y >> r;
    44.         q.push({x, y, r, false});
    45.     }
    46.    
    47.     // BFS处理引爆过程
    48.     while (!q.empty()) {
    49.         Point current = q.front();
    50.         q.pop();
    51.         
    52.         // 计算当前爆炸影响范围
    53.         int min_x = current.x - current.r;
    54.         int max_x = current.x + current.r;
    55.         int min_y = current.y - current.r;
    56.         int max_y = current.y + current.r;
    57.         
    58.         // 遍历范围内的所有可能位置
    59.         for (int x = min_x; x <= max_x; ++x) {
    60.             for (int y = min_y; y <= max_y; ++y) {
    61.                 // 距离检查(使用平方比较优化)
    62.                 if (distance2(current.x, current.y, x, y) > current.r * current.r)
    63.                     continue;
    64.                
    65.                 // 检查该位置是否存在炸雷
    66.                 if (mines.find(x) != mines.end() && mines[x].find(y) != mines[x].end()) {
    67.                     for (auto& mine : mines[x][y]) {
    68.                         if (!mine.exploded) {
    69.                             mine.exploded = true;
    70.                             count++;
    71.                             q.push(mine); // 新引爆的炸雷加入队列
    72.                         }
    73.                     }
    74.                 }
    75.             }
    76.         }
    77.     }
    78.    
    79.     cout << count << endl;
    80.     return 0;
    81. }
    复制代码

    四、关键算法点详解
    • BFS队列应用:使用队列管理待处理的爆炸点
    • 哈希表存储优化:O(1)时间复杂度快速查找指定位置炸雷
    • 爆炸范围处理:通过整数范围遍历+距离验证确保准确性
    • 状态标记:exploded字段防止重复计数

    五、性能优化技巧
    • 使用距离平方比较避免浮点运算
    • unordered_map实现快速查找
    • 提前终止条件判断


    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    快速回复 返回顶部 返回列表