点击跳转
小明最近迷上了一款名为《扫雷》的游戏。
其中有一个关卡的任务如下:
在一个二维平面上放置着 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,表示一个排雷火箭的信息。
输出格式 输出一个整数表示答案。
数据范围
对于 40% 的评测用例:0≤x,y≤109,0≤n,m≤103,1≤r≤10,
对于 100% 的评测用例:0≤x,y≤109,0≤n,m≤5×104,1≤r≤10。
2 1
2 2 4
4 4 2
0 0 5
2
n
次,那么时间复杂度就变成了 O( n 2 {n^2} n2),但是还是过不了/*
* @Author: suhuamo
* @Date: 2022-04-13 15:23:54
* @LastEditTime: 2022-04-15 22:43:53
* @FilePath: \algorithm\蓝桥杯\第十三届蓝桥杯省赛B\H.cpp
* @slogan: 也许散落在浩瀚宇宙的小行星们也知道
* 知识点: 哈希+建图
*/
#include
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int N = 5e4 + 10, M = 1e6 + 7, X = 1e9 + 1;
struct node
{
int x, y, r;
}boom[N];
int n, m;
/** hs 是 hash 数组*/
LL hs[M];
/** id 代表对应的 hash 数组的这个点是哪个炸弹 */
int id[M];
/** st 代表对应的 hash 数组的这个点是否炸了 */
bool st[M];
LL get_hs(int x, int y)
{
return (LL)x * X + y;
}
int find(int x, int y)
{
LL hs_k = get_hs(x, y);
int k = (hs_k % M + M) % M;
while(hs[k] != -1 && hs[k] != hs_k)
{
k++;
if(k == M) k = 0;
}
return k;
}
bool check(int x1, int y1, int r, int x2, int y2)
{
LL d = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
// 如果炸得到
if(d <= (LL)r * r) return true;
return false;
}
void bfs(int x, int y)
{
int k = find(x, y);
queue<int> q;
q.push(k);
st[k] = true;
while(!q.empty())
{
int k = q.front();
q.pop();
int i = id[k];
int r = boom[i].r, x = boom[i].x, y = boom[i].y;
for(int x1 = x - r; x1 <= x + r; x1++)
for(int y1 = y - r; y1 <= y + r; y1++)
{
k = find(x1, y1);
if(id[k] && !st[k] && check(x, y, r, x1, y1))
{
q.push(k);
st[k] = true;
}
}
}
}
int main()
{
memset(hs, -1, sizeof hs);
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++)
{
int x, y, r;
scanf("%d%d%d", &x, &y, &r);
boom[i] = {x, y, r};
// 进行hash映射
int k = find(x, y);
if(hs[k] == -1) hs[k] = get_hs(x, y);
// 如果这个位置第一次出现点,那么保存||如果这个点出现了两个炸弹,那么取半径最大的那个炸弹就可以了
if(id[k] == 0 || boom[id[k]].r < r) id[k] = i;
}
for(int i = 0; i < m; i++)
{
int x, y, r;
scanf("%d%d%d", &x, &y, &r);
for(int x1 = x - r; x1 <= x + r; x1++)
for(int y1 = y - r; y1 <= y + r; y1++)
{
int k = find(x1, y1);
// 如果该点有雷,并且没被炸过,并且可以被炸
if(id[k] && !st[k] && check(x, y, r, x1, y1)) bfs(x1, y1);
}
}
int res = 0;
for(int i = 1; i <= n; i++)
{
int k = find(boom[i].x, boom[i].y);
// 如果这个地方被炸了
if(st[k]) res++;
}
printf("%d\n",res);
return 0;
}