習題地址 https://www.acwing.com/problem/content/description/530/node
現有一塊大奶酪,它的高度爲h,它的長度和寬度咱們能夠認爲是無限大的,奶酪中間有許多半徑相同的球形空洞。ios
咱們能夠在這塊奶酪中創建空間座標系,在座標系中,奶酪的下表面爲z=0,奶酪的上表面爲z=h。 nginx
如今,奶酪的下表面有一隻小老鼠Jerry,它知道奶酪中全部空洞的球心所在的座標。ide
若是兩個空洞相切或是相交,則Jerry能夠從其中一個空洞跑到另外一個空洞,特別地,若是一個空洞與下表面相切或是相交,Jerry則能夠從奶酪下表面跑進空洞;若是一個空洞與上表面相切或是相交,Jerry則能夠從空洞跑到奶酪上表面。atom
位於奶酪下表面的Jerry想知道,在不破壞奶酪的狀況下,可否利用已有的空洞跑到奶酪的上表面去? spa
空間內兩點P1(x1,y1,z1)、P2(x2,y2,z2)𝑃1(𝑥1,𝑦1,𝑧1)、𝑃2(𝑥2,𝑦2,𝑧2)的距離公式以下:3d
每一個輸入文件包含多組數據。 code
輸入文件的第一行,包含一個正整數T,表明該輸入文件中所含的數據組數。 xml
接下來是T組數據,每組數據的格式以下:blog
第一行包含三個正整數n,h和r,兩個數之間以一個空格分開,分別表明奶酪中空洞的數量,奶酪的高度和空洞的半徑。
接下來的n行,每行包含三個整數x、y、z,兩個數之間以一個空格分開,表示空洞球心座標爲(𝑥,𝑦,𝑧)。
輸出文件包含T行,分別對應T組數據的答案,若是在第i組數據中,Jerry能從下表面跑到上表面,則輸出「Yes」,若是不能,則輸出「No」(均不包含引號)。
1≤n≤10001≤n≤1000,
1≤h,r≤1091≤h,r≤109,
T≤20T≤20,
座標的絕對值不超過109109
輸入樣例:
3 2 4 1 0 0 1 0 0 3 2 5 1 0 0 1 0 0 4 2 5 2 0 0 2 2 0 4
輸出樣例:
Yes No Yes
一種直接搜索 剪枝,一種使用能聯通的孔記錄並查集,尋找聯通上下層的孔是否在一個集合
解法1 BFS搜索
1 #include <iostream> 2 #include <queue> 3 #include <memory.h> 4 #include <math.h> /* sqrt */ 5 6 using namespace std; 7 8 9 struct node{ 10 double x,y,z; 11 }; 12 13 const int N = 1010; 14 node a[N]; 15 int vis[N],n,h,r,t; 16 queue<node> q; 17 18 double distance(node a,node b) 19 { 20 double nx = a.x-b.x,ny = a.y-b.y,nz = a.z-b.z; 21 double ans = sqrt(nx*nx+ny*ny+nz*nz); 22 return ans; 23 } 24 25 int bfs() 26 { 27 while(!q.empty()){ 28 if(q.front().z+r >= h) 29 return 1; 30 node currentNode = q.front(); 31 q.pop(); 32 //計算該點和其餘點是否能夠鏈接走動 33 for(int i = 1;i <= n;i++){ 34 if( ( 2*r >= distance(currentNode,a[i]) ) && vis[i] != 1 ){ 35 q.push(a[i]); 36 vis[i] =1; 37 if(q.front().z+r >= h) 38 return 1; 39 } 40 } 41 } 42 43 return 0; 44 } 45 46 47 int main() 48 { 49 cin >> t; 50 51 while(t--){ 52 53 cin >> n >> h >> r; 54 55 //初始化 56 q = queue<node>(); 57 memset(vis,0,sizeof(vis)); 58 59 for(int i = 1;i <= n;i++){ 60 cin >> a[i].x >> a[i].y>>a[i].z; 61 if(a[i].z <= r){ 62 q.push(a[i]); 63 vis[i] = 1; 64 } 65 } 66 67 if(bfs()){ 68 cout << "Yes" << endl; 69 }else{ 70 cout << "No"<<endl; 71 } 72 73 } 74 75 76 return 0; 77 }
解法2 並查集
1 #include <cstdio> 2 #include <vector> 3 #include <cstdlib> 4 5 using namespace std; 6 7 struct point{ 8 long long x,y,z; 9 void write(int a,int b,int c){x= a;y = b;z= c;} 10 }; 11 point pts[1001]; 12 unsigned long long h,r,n; int T; 13 unsigned long long disSqu(int a,int b){ 14 unsigned long long res = (pts[a].x-pts[b].x)*(pts[a].x-pts[b].x) + 15 (pts[a].y-pts[b].y)*(pts[a].y-pts[b].y) + (pts[a].z-pts[b].z)*(pts[a].z-pts[b].z); 16 return res; 17 } 18 19 int parent[1001]; 20 void init(){ 21 for(int i = 1;i <=n;i++) 22 parent[i] = i; 23 } 24 25 int find(int cu){ 26 return parent[cu] == cu? cu:parent[cu] = find(parent[cu]); 27 } 28 29 void merge(int a,int b) 30 { 31 int x = find(a),y = find(b); 32 if(x < y) parent[y] = x; 33 else parent[x] = y; 34 } 35 36 vector<int> but,top; 37 38 int main() 39 { 40 vector<int>::iterator it1,it2; 41 bool flag; 42 unsigned long long lim;long long a,b,c; 43 scanf("%d",&T); 44 for(int z = 1;z <= T;z++){ 45 scanf("%lld %lld %lld",&n,&h,&r); 46 but.clear();top.clear();init();flag = false; 47 lim = r*r*4; 48 for(int i = 1;i <= n; i++){ 49 scanf("%lld %lld %lld",&a,&b,&c); 50 pts[i].write(a,b,c); 51 if(c<=r){but.push_back(i);} 52 if(c>=h-r){top.push_back(i);} 53 } 54 if(h <= r) { printf("Yes\n");continue; } 55 for(int i = 1;i <= n;i++){ 56 for(int j = i+1;j <= n;j++){ 57 if(disSqu(i,j) <= lim) merge(i,j); 58 } 59 } 60 61 for(it1 = top.begin();it1 != top.end();it1++){ 62 for(it2 = but.begin();it2 != but.end();it2++){ 63 if(find(*it1) == find(*it2)){ 64 printf("Yes\n"); 65 flag= true; 66 break; 67 } 68 } 69 if(flag) break; 70 } 71 72 if(!flag) printf("No\n"); 73 } 74 75 return 0; 76 }