蓝桥杯 - 试题 H: 扫雷(思维)
生活随笔
收集整理的這篇文章主要介紹了
蓝桥杯 - 试题 H: 扫雷(思维)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題目大意:給出 nnn 個地雷和 mmm 個炸彈,都以 (x,y,r)(x,y,r)(x,y,r) 的形式給出,意義分別如下:
問使用過 mmm 個炸彈后,一共可以引爆多少個地雷
題目分析:(賽時讀錯題了,怪不得當時算復雜度的時候能多算一個 logloglog 出來)
最初的思想肯定是,先讓可以“連鎖反應”的地雷建立關系,這樣引爆其中的一個地雷后,由“連鎖反應”所引爆的地雷就不會被重復判斷了,可以做到每個地雷至多被遍歷一次。
需要發現一個很重要的細節就是,地雷引爆的關系是單向的,如果地雷 A 可以引爆地雷 B ,不一定能得出地雷 B 可以引爆地雷 A
所以整個“連鎖反應”是一個有向圖,不能使用并查集處理連通性。在建出有向圖后索性直接用 dfs 暴力遍歷即可,因為上面的思路已經保證了每個地雷至多遍歷一次,所以 dfs 的復雜度是線性的
現在的問題轉換為該如何快速建邊,觀察數據范圍不難發現半徑 rrr 給的特別小,所以可以將圓心用 map 映射一下,然后每次只需要遍歷圓內的點嘗試建邊就好了
時間復雜度:O(n?320?logn)O(n*320*logn)O(n?320?logn),這里的 320320320 代表的是半徑為 101010 的圓內的點數
代碼:
#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: 扫雷(思维)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 蓝桥杯 - 试题 J: 砍竹子(双向链表
- 下一篇: 纹理与图片的区别