【洛谷】P8785 [蓝桥杯 2022 省 B] 扫雷 的题解
题目传送门
思路
定义结构体储存 ( x , y , r , f l a g ) (x,y,r,flag) (x,y,r,flag),分别表示坐标,爆炸半径,以及是否已爆炸。依次引爆排雷火箭,搜索到一个雷如果在爆炸范围内继续递归搜索。但时间复杂度为 O ( m n ) O(mn) O(mn),只能拿到前 40 40 40 分。
题目中每一个雷的爆炸范围与他们之间的距离相比实在是太小了,所以深搜过程中对与所有个雷的判断很多余。我们只要在一开始先对每一个雷进行按 x x x 位置进行从小到大排序,这样每次搜索的 x x x 范围是 x − r → x + r x−r→ x+r x−r→x+r,范围之外的可以直接排除,剩下的一小部分才是要真正要搜索的。在判断搜索范围时,使用二分查找来实现,这样可以达到优化作用。
此题不可以用并查集去做,因为雷的爆炸是由方向的, A A A 雷爆炸可以引爆 B B B 雷,但是 B B B 雷爆炸是有可能无法引爆 B B B 雷的(爆炸半径不同)
正解是深搜,为了避免边被卡成 O ( n 2 ) O(n^2) O(n2),以至于超时。因此我们就需要去除重复的点,记录每一个坐标下点的位置。
然后把每一个火箭作为根节点,去遍历周围 r 2 r^2 r2 的雷,统计一下一共能炸多少雷就可以。
代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <climits>
#include <algorithm>
#include <map>
#include <queue>
#include <vector>
#include <ctime>
#include <string>
#include <cstring>
#define lowbit(x) x & (-x)
#define endl "\n"
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
namespace fastIO {
inline int read() {
register int x = 0, f = 1;
register char c = getchar();
while (c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
inline void write(int x) {
if(x < 0) putchar('-'), x = -x;
if(x > 9) write(x / 10);
putchar(x % 10 + '0');
return;
}
}
using namespace fastIO;
struct Node {
int x, y, r, l;
}a[200005];
unordered_map <ll, int> idx;
bool st[200005];
int n, m, cnt, ans;
ll cal(int x, int y) {
return (ll)x * (1000000000 + 1) + y;
}
bool solve(int x, int y, int r) {
if(x * x + y * y <= r * r) return true;
else return false;
}
void dfs(int i) {
st[i] = true;
ans += a[i].l;
int r = a[i].r;
for(int x = max(a[i].x - r, 0); x <= min(a[i].x + r, 1000000000); x ++) {
for(int y = max(a[i].y - r, 0); y <= min(a[i].y + r, 1000000000); y ++) {
if(solve(x - a[i].x, y - a[i].y, r)) {
ll xy = cal(x, y);
if(idx.count(xy)) {
int u = idx[xy];
if(!st[u]) {
dfs(u);
}
}
}
}
}
}
int main() {
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
cin >> n >> m;
for(int i = 1; i <= n; i ++ ) {
int x, y, r;
cin >> x >> y >> r;
ll xy = cal(x, y);
if(idx.find(xy) == idx.end()) {
idx[xy] = ++cnt;
a[cnt] = {x, y, r, 1};
}
else {
int u = idx[xy];
a[u].r = max(a[u].r, r);
++ a[u].l;
}
}
for(int i = 1; i <= m; i ++) {
int x, y, r;
cin >> x >> y >> r;
a[cnt + 1] = {x, y, r};
dfs(cnt + 1);
}
cout << ans;
return 0;
}