炸雷!(地址映射+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::mapstd::unordered_map 将坐标 (x, y) 映射到该位置上的炸雷信息(记录半径和数量)。为了处理哈希冲突和坐标组合,通常将 xy 转化成一个唯一键,例如 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;

}

相关推荐
大模型码小白3 小时前
AI 对话流性能调优:万级消息的虚拟滚动落地
java·大数据·前端·javascript·人工智能·算法·机器学习
sel_94 小时前
【多轮对话论文导读(三)】多轮对话与Agent论文阅读笔记:用户模拟、轨迹生成与长期记忆
论文阅读·人工智能·笔记·深度学习·算法·机器学习
Asize4 小时前
438. 找到字符串中所有字母异位词
算法
Asize5 小时前
283. 移动零
算法
船厂电气自动化ai大模型6 小时前
AI大模型与数学·第57课 傅里叶全套工具链综合实战:串联级数/连续变换/DFT/FFT,图像、音频、扩散模型完整例题
数据结构·人工智能·深度学习·算法·机器学习
人工智能培训7 小时前
人工智能数据安全下的个人信息保护实践方案
大数据·人工智能·算法·生活
元启数宇8 小时前
幕墙AI设计算法逻辑:元启数宇如何智能分格
人工智能·算法
宵时待雨8 小时前
优选算法专题16:多源BFS
算法·宽度优先
重生之后端学习8 小时前
53. 最大子数组和[中等]✅
java·数据结构·算法·leetcode·职场和发展
INGNIGHT9 小时前
1908 · 布尔表达式求值(stack单调栈&dfs)
开发语言·c++·算法