2022第十三屆藍橋杯B組C++省賽H題 掃雷
【問題描述】
小明最近迷上了一款名為《掃雷》的遊戲。其中有一個關卡的任務如下, 在一個二維平面上放置著 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,表示一個排雷火箭的資訊。
【輸出格式】
輸出一個整數表示答案。
【樣例輸入】
2 1
2 2 4
4 4 2
0 0 5
【樣例輸出】
2
【樣例說明】
示例圖如下,排雷火箭 1 覆蓋了炸雷 1,所以炸雷 1 被排除;炸雷 1 又覆 蓋了炸雷 2,所以炸雷 2 也被排除。
【評測用例規模與約定】
對於 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.
當時用dfs做的,最後一分鐘還在掙扎在找錯誤TuT....
昨天看到到:“直接兩重迴圈建邊+dfs搜尋的,會炸(因為建邊是兩重迴圈,過不叫第二個5e4的樣例)”
一個只過了民間資料40%的程式碼(...):
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=50100; 4 //炸雷的座標和半徑 5 int x_pos[maxn]; 6 int y_pos[maxn]; 7 int radius[maxn]; 8 bool vis[maxn];//標記是否爆炸 9 10 struct point11 { 12 int x,y,r; 13 //將結構體放入 map 中作為鍵,需要自己寫一個 operator 來排序 14 bool operator<(const point &p)const 15 { 16 if(x==p.x) 17 { 18 if(y==p.y) 19 return r<p.r; 20 return y<p.y; 21 } 22 return x<p.x; 23 } 24 }; 25 26 map<point,int>all; 27 28 double getdis(int x1,int y1,int x2,int y2) 29 { 30 return sqrt((x1-x2)*(x1-x2)-(y1-y2)*(y1-y2)); 31 } 32 33 int bfs(point begin,int n) 34 { 35 int cnt=0; 36 queue<point>q; 37 q.push(begin); 38 while(!q.empty()) 39 { 40 point cur=q.front(); 41 q.pop(); 42 //遍歷排雷火箭所在的最小正方形,找到其涉及爆炸的雷 43 for(int i=cur.x-cur.r;i<=cur.x+cur.r;i++) 44 { 45 for(int j=cur.y-cur.r;j<=cur.y+cur.r;j++) 46 { 47 if(getdis(i,j,cur.x,cur.y)>cur.r) 48 continue; 49 point temp; 50 temp.x=i; 51 temp.y=j; 52 for(int k=0;k<n;k++) 53 { 54 if(!vis[k]&&x_pos[k]==temp.x&&y_pos[k]==temp.y) 55 { 56 temp.r=radius[k]; 57 q.push(temp); 58 cnt++; 59 vis[k]=true;//標記已炸 60 all[temp]--; 61 } 62 } 63 } 64 } 65 } 66 return cnt; 67 } 68 69 int main() 70 { 71 int n,m,cnt=0; 72 cin>>n>>m; 73 for(int i=0;i<n;i++) 74 { 75 cin>>x_pos[i]>>y_pos[i]>>radius[i]; 76 vis[i]=false;//初始化全部未炸 77 } 78 for(int i=0;i<m;i++) 79 { 80 point p; 81 cin>>p.x>>p.y>>p.r; 82 cnt+=bfs(p,n); 83 } 84 cout<<cnt; 85 return 0; 86 }