小明最近迷上了一款名为《扫雷》的游戏。其中有一个关卡的任务如下,在一个二维平面上放置着 nnn 个炸雷,第 iii 个炸雷 (xi,yi,ri)\left(x_{i}, y_{i}, r_{i}\right)(xi,yi,ri) 表示在坐标 (xi,yi)\left(x_{i}, y_{i}\right)(xi,yi) 处存在一个炸雷,它的爆炸范围是以半径为 rir_{i}ri 的一个圆。
为了顺利通过这片土地,需要玩家进行排雷。玩家可以发射 mmm 个排雷火箭,小明已经规划好了每个排雷火箭的发射方向,第 jjj 个排雷火箭 (xj,yj,rj)\left(x_{j}, y_{j}, r_{j}\right)(xj,yj,rj) 表示这个排雷火箭将会在 (xj,yj)\left(x_{j}, y_{j}\right)(xj,yj) 处爆炸,它的爆炸范围是以半径为 rjr_{j}rj 的一个圆,在其爆炸范围内的炸雷会被引爆。同时,当炸雷被引爆时,在其爆炸范围内的炸雷也会被引爆。现在小明想知道他这次共引爆了几颗炸雷?
你可以把炸雷和排雷火箭都视为平面上的一个点。一个点处可以存在多个炸雷和排雷火箭。当炸雷位于爆炸范围的边界上时也会被引爆。
输入的第一行包含两个整数 nnn、mmm。
接下来的 nnn 行, 每行三个整数 xi,yi,rix_{i}, y_{i}, r_{i}xi,yi,ri, 表示一个炸雷的信息。
再接下来的 mmm 行,每行三个整数 xj,yj,rjx_{j}, y_{j}, r_{j}xj,yj,rj, 表示一个排雷火箭的信息。
输出一个整数表示答案。
2 1
2 2 4
4 4 2
0 0 5
2
【样例说明】
示例图如下, 排雷火箭 1 覆盖了炸雷 1 , 所以炸雷 1 被排除; 炸雷 1 又覆 盖了炸雷 2 , 所以炸雷 2 也被排除。

【评测用例规模与约定】
对于 40%40 \%40% 的评测用例: 0≤x,y≤109,0≤n,m≤103,1≤r≤100 \leq x, y \leq 10^{9}, 0 \leq n, m \leq 10^{3}, 1 \leq r \leq 100≤x,y≤109,0≤n,m≤103,1≤r≤10.
对于 100%100 \%100% 的评测用例: 0≤x,y≤109,0≤n,m≤5×104,1≤r≤100 \leq x, y \leq 10^{9}, 0 \leq n, m \leq 5 \times 10^{4}, 1 \leq r \leq 100≤x,y≤109,0≤n,m≤5×104,1≤r≤10.
蓝桥杯 2022 省赛 B 组 H 题。
1.这个一看就是一个深度优先遍历的题如果直接深度优先搜索做只能得50分,别问我怎么知道的。
2.这个题不能用并查集做,如果把那些老默跟着高启强干,不知道哪个老默就先死了(炸了),所以只能用深度优先遍历做
3.那么深度优先遍历就要减去一些范围我们知道这个玩意的x在小于x-r的范围上是肯定不会爆炸的,在大于x+r的范围上也是肯定不会爆炸的,所以排除掉这些以外的点进行深度优先遍历就行了,而找到边界值的最快的方法是二分查找所以这个题就有一下思路
struct boom
{long long x;long long y;long long r;bool zha;
};struct huojian
{long long x;long long y;long long r;
};int main()
{cin >> n >> m;for (int i = 0; i < n; i++){boom b;cin >> b.x >> b.y >> b.r;b.zha = false;booms.push_back(b);}for (int i = 0; i < m; i++){/* code */huojian h;cin >> h.x >> h.y >> h.r;huojians.push_back(h);}
bool cmp(boom b1, boom b2)
{return (b1.x < b2.x);
}sort(booms.begin(), booms.end(), cmp);
void dfs(long long x, long long y, long long ri)for (int i = 0; i < m; i++){dfs(huojians[i].x, huojians[i].y, huojians[i].r);}
long long lmid, rmid, l = 0, r = n - 1;// 找左边界左边界外的都排除掉while (l <= r){lmid = (l + r) / 2; // 取中点// 把小于r的外面的炸弹排除掉先if (booms[lmid].x < x - ri){l = lmid + 1;}else if (booms[lmid].x == x - ri){break;}else{r = lmid - 1;}}lmid = l; // 确认左边界// 找右边界,右边界外的都排除掉l = 1, r = n;while (l <= r){rmid = (l + r) / 2;if (booms[rmid].x < x + ri){l = rmid + 1;}else if (booms[rmid].x == x + ri){break;}else{r = rmid - 1;}}rmid = r;
在使用sort的时候 sort(booms.begin(), booms.end(), cmp);如果用vector的话要这样写,如果按传统数组那样写会报错。
这个题的精髓就是要用二分缩小一下范围。
当然在考场上直接用dfs也能得到50分呢~~~~~~多良心···
#include
#include
#include
#include using namespace std;
int n, m;int res = 0;
struct boom
{long long x;long long y;long long r;bool zha;
};struct huojian
{long long x;long long y;long long r;
};vector booms;
vector huojians;double dis(double x1, double x2, double y1, double y2)
{return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}bool cmp(boom b1, boom b2)
{return (b1.x < b2.x);
}void dfs(long long x, long long y, long long ri)
{long long lmid, rmid, l = 0, r = n - 1;// 找左边界左边界外的都排除掉while (l <= r){lmid = (l + r) / 2; // 取中点// 把小于r的外面的炸弹排除掉先if (booms[lmid].x < x - ri){l = lmid + 1;}else if (booms[lmid].x == x - ri){break;}else{r = lmid - 1;}}lmid = l; // 确认左边界// 找右边界,右边界外的都排除掉l = 1, r = n;while (l <= r){rmid = (l + r) / 2;if (booms[rmid].x < x + ri){l = rmid + 1;}else if (booms[rmid].x == x + ri){break;}else{r = rmid - 1;}}rmid = r;for (long long i = lmid; i <= rmid; i++){if (!booms[i].zha && dis(booms[i].x, x, booms[i].y, y) <= ri){booms[i].zha = true;res++;dfs(booms[i].x, booms[i].y, booms[i].r);}}
}int main()
{cin >> n >> m;for (int i = 0; i < n; i++){boom b;cin >> b.x >> b.y >> b.r;b.zha = false;booms.push_back(b);}for (int i = 0; i < m; i++){/* code */huojian h;cin >> h.x >> h.y >> h.r;huojians.push_back(h);}sort(booms.begin(), booms.end(), cmp);for (int i = 0; i < m; i++){dfs(huojians[i].x, huojians[i].y, huojians[i].r);}cout << res;system("pause");
}