炸雷!(地址映射+dfs搜索)

小明最近迷上了一款名为《扫雷》的游戏。其中有一个关卡的任务如下, 在一个二维平面上放置着 n 个炸雷,第 i 个炸雷 (xi , yi ,ri) 表示在坐标 (xi , yi) 处存在一个炸雷,它的爆炸范围是以半径为 ri 的一个圆。

为了顺利通过这片土地,需要玩家进行排雷。玩家可以发射 m 个排雷火箭,小明已经规划好了每个排雷火箭的发射方向,第 j 个排雷火箭 (xj , yj ,rj) 表示这个排雷火箭将会在 (xj , yj) 处爆炸,它的爆炸范围是以半径为 rj 的一个圆,在其爆炸范围内的炸雷会被引爆。同时,当炸雷被引爆时,在其爆炸范围内的炸雷也会被引爆。现在小明想知道他这次共引爆了几颗炸雷?

你可以把炸雷和排雷火箭都视为平面上的一个点。一个点处可以存在多个炸雷和排雷火箭。当炸雷位于爆炸范围的边界上时也会被引爆。

输入格式

输入的第一行包含两个整数 n、m.

接下来的 n 行,每行三个整数 xi , yi ,ri,表示一个炸雷的信息。

再接下来的 m 行,每行三个整数 xj , yj ,rj,表示一个排雷火箭的信息。

输出格式

输出一个整数表示答案。

样例输入

复制代码
2 1
2 2 4
4 4 2
0 0 5

样例输出

复制代码
2

提示

示例图如下,排雷火箭 1 覆盖了炸雷 1,所以炸雷 1 被排除;炸雷 1 又覆盖了炸雷 2,所以炸雷 2 也被排除。

对于 40% 的评测用例:0 ≤ x, y ≤ 1e9 , 0 ≤ n, m ≤ 1e3 , 1 ≤ r ≤ 10.

对于 100% 的评测用例:0 ≤ x, y ≤ 1e9 , 0 ≤ n, m ≤ 5 × 1e4 , 1 ≤ r ≤ 10.

这个问题是一个典型的圆覆盖与连锁反应 问题,本质上可以抽象为图的遍历(DFS/BFS)。

核心挑战

  1. 连锁反应:火箭引爆炸雷,炸雷再引爆炸雷。这构成了一个有向图的搜索问题。

  2. 坐标范围巨大:x, y高达 10^9,无法使用二维数组。

  3. 圆心距离计算:判断点 (x1, y1) 是否在半径为 r 的圆 (x0, y0, r) 内,公式为:

    (x1-x0)^2+(y1-y0)^2<=r^2

  4. 爆炸半径很小 :注意到提示中 r ≤ 10.,这是一个非常关键的突破口。

优化思路:哈希表 + 邻域搜索

由于坐标极大但半径很小,我们可以将所有炸雷的坐标通过**哈希(Hash)**存储。

  • 存储 :使用 std::map 或 std::unordered_map 将坐标 (x, y) 映射到该位置上的炸雷信息(记录半径和数量)。为了处理哈希冲突和坐标组合,通常将 x 和 y 转化成一个唯一键,例如 key = x * OFFSET + y。

  • 搜索范围 :对于一个爆炸圆 (x, y, r),我们不需要遍历所有 n个炸雷。由于 r ≤ 10.,我们只需要搜索 x 坐标在 x-r, x+r 且 y 坐标在 y-r, y+r 范围内的点即可。

  • 去重:一旦某个坐标上的炸雷被引爆,就标记为已访问,防止死循环。

#include <iostream>

#include <vector>

#include <unordered_map>

#include <cmath>

using namespace std;

typedef long long LL;

// 炸雷结构体

struct Mine {

int x, y, r, num;

bool visited;

};

// 哈希函数,将坐标映射为唯一 key

const LL OFFSET = 1000000001LL;

unordered_map<LL, int> pos_to_id;

vector<Mine> mines;

// 距离平方计算

LL get_dist_sq(LL x1, LL y1, LL x2, LL y2) {

return (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);

}

int ans = 0;

void dfs(int id) {

minesid.visited = true;

ans += minesid.num;

LL x = minesid.x;

LL y = minesid.y;

LL r = minesid.r;

// 只搜索半径范围内的格子

for (LL i = x - r; i <= x + r; i++) {

for (LL j = y - r; j <= y + r; j++) {

LL key = i * OFFSET + j;

if (pos_to_id.count(key)) {

int next_id = pos_to_idkey;

if (!minesnext_id.visited && get_dist_sq(x, y, i, j) <= r * r) {

dfs(next_id);

}

}

}

}

}

int main() {

ios::sync_with_stdio(false);

cin.tie(nullptr);

int n, m;

cin >> n >> m;

for (int i = 0; i < n; i++) {

int x, y, r;

cin >> x >> y >> r;

LL key = (LL)x * OFFSET + y;

if (pos_to_id.count(key)) {

int id = pos_to_idkey;

minesid.r = max(minesid.r, r); // 同一位置取半径最大的

minesid.num++;

} else {

pos_to_idkey = mines.size();

mines.push_back({x, y, r, 1, false});

}

}

for (int i = 0; i < m; i++) {

int x, y, r;

cin >> x >> y >> r;

// 火箭引爆炸雷

for (LL i_x = x - r; i_x <= x + r; i_x++) {

for (LL j_y = y - r; j_y <= y + r; j_y++) {

LL key = i_x * OFFSET + j_y;

if (pos_to_id.count(key)) {

int id = pos_to_idkey;

if (!minesid.visited && get_dist_sq(x, y, i_x, j_y) <= (LL)r * r) {

dfs(id);

}

}

}

}

}

cout << ans << endl;

return 0;

}

相关推荐
yi0115 小时前
LeetCode 219:存在重复元素 II——哈希表记录“最近一次出现的位置”
数据结构·人工智能·笔记·python·算法·leetcode·哈希表
灯澜忆梦8 小时前
【面向对象编程C++】| 基础语法
java·c++·算法
小蒋观天下8 小时前
专项方案:大场景港口AI安防、多干扰环境下的算法调优与落地实操
人工智能·深度学习·算法·安全·机器学习·计算机视觉·ai大模型
Evand J8 小时前
【电机滤波例程5】渐消因子自适应扩展卡尔曼滤波(EKF),MATLAB。PMSM负载突变下的状态估计。附下载链接
算法·matlab
H.莓飛9 小时前
【数据结构】二叉树_OJ题
linux·开发语言·数据结构·算法
好想像大佬一样能够ak所有9 小时前
Leetcode35.搜索插入位置
数据结构·算法·leetcode
aqiu1111119 小时前
【C++算法打怪专栏】LeetCode 165. 比较版本号(双指针与字符串流法)
c++·算法·leetcode
黄金龙PLUS9 小时前
如何基于置换算法来设计对称加密算法
算法·网络安全·密码学·哈希算法·同态加密
不会就选b10 小时前
算法日常・每日刷题--<动态规划>14
算法
赛博守夜人10 小时前
跨境业务与出海合规之九:海外买量投放与营销虚假流量(Ad Fraud):跨国机房群控与归因欺诈识别算法
算法·安全