蓝桥杯 - 试题 H: 扫雷(思维)
Posted Frozen_Guardian
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了蓝桥杯 - 试题 H: 扫雷(思维)相关的知识,希望对你有一定的参考价值。
题目大意:给出
n
n
n 个地雷和
m
m
m 个炸弹,都以
(
x
,
y
,
r
)
(x,y,r)
(x,y,r) 的形式给出,意义分别如下:
- 对于每个地雷,位于点 ( x , y ) (x,y) (x,y),爆炸后会波及半径为 r r r 的圆形区域
- 对于每个炸弹,会在点 ( x , y ) (x,y) (x,y) 爆炸,爆炸后会引爆半径为 r r r 的圆形区域内的地雷,随后地雷会 “连锁反应” 的爆炸
问使用过 m m m 个炸弹后,一共可以引爆多少个地雷
题目分析:(赛时读错题了,怪不得当时算复杂度的时候能多算一个 l o g log log 出来)
最初的思想肯定是,先让可以“连锁反应”的地雷建立关系,这样引爆其中的一个地雷后,由“连锁反应”所引爆的地雷就不会被重复判断了,可以做到每个地雷至多被遍历一次。
需要发现一个很重要的细节就是,地雷引爆的关系是单向的,如果地雷 A 可以引爆地雷 B ,不一定能得出地雷 B 可以引爆地雷 A
所以整个“连锁反应”是一个有向图,不能使用并查集处理连通性。在建出有向图后索性直接用 dfs 暴力遍历即可,因为上面的思路已经保证了每个地雷至多遍历一次,所以 dfs 的复杂度是线性的
现在的问题转换为该如何快速建边,观察数据范围不难发现半径 r r r 给的特别小,所以可以将圆心用 map 映射一下,然后每次只需要遍历圆内的点尝试建边就好了
时间复杂度: O ( n ∗ 320 ∗ l o g n ) O(n*320*logn) O(n∗320∗logn),这里的 320 320 320 代表的是半径为 10 10 10 的圆内的点数
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=5e4+100;
struct Point
int x,y,r;
void input()
scanf("%d%d%d",&x,&y,&r);
p1[N],p2[N];
bool vis[N];
map<pair<int,int>,vector<int>>mp;
vector<int>node[N];
int dfs(int u)
if(vis[u])
return 0;
vis[u]=true;
int ans=1;
for(auto v:node[u])
ans+=dfs(v);
return ans;
int main()
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
p1[i].input();
mp[p1[i].x,p1[i].y].push_back(i);
for(int i=1;i<=m;i++)
p2[i].input();
for(int i=1;i<=n;i++)
for(int dx=-10;dx<=10;dx++)
for(int dy=-10;dy<=10;dy++)
LL x=p1[i].x,y=p1[i].y;
LL xx=x+dx,yy=y+dy;
LL r=p1[i].r;
if((x-xx)*(x-xx)+(y-yy)*(y-yy)<=r*r)
for(auto j:mp[xx,yy])
node[i].push_back(j);
int ans=0;
for(int i=1;i<=m;i++)
for(int dx=-10;dx<=10;dx++)
for(int dy=-10;dy<=10;dy++)
LL x=p2[i].x,y=p2[i].y;
LL xx=x+dx,yy=y+dy;
LL r=p2[i].r;
if((x-xx)*(x-xx)+(y-yy)*(y-yy)<=r*r)
for(auto j:mp[xx,yy])
ans+=dfs(j);
cout<<ans<<endl;
return 0;
以上是关于蓝桥杯 - 试题 H: 扫雷(思维)的主要内容,如果未能解决你的问题,请参考以下文章