acwing 528. 奶酪 解题记录
习题地址 https://www.acwing.com/problem/content/description/530/
现有一块大奶酪,它的高度为h,它的长度和宽度我们可以认为是无限大的,奶酪中间有许多半径相同的球形空洞。
我们可以在这块奶酪中建立空间坐标系,在坐标系中,奶酪的下表面为z=0,奶酪的上表面为z=h。
现在,奶酪的下表面有一只小老鼠Jerry,它知道奶酪中所有空洞的球心所在的坐标。
如果两个空洞相切或是相交,则Jerry可以从其中一个空洞跑到另一个空洞,特别地,如果一个空洞与下表面相切或是相交,Jerry则可以从奶酪下表面跑进空洞;如果一个空洞与上表面相切或是相交,Jerry则可以从空洞跑到奶酪上表面。
位于奶酪下表面的Jerry想知道,在不破坏奶酪的情况下,能否利用已有的空洞跑到奶酪的上表面去?
空间内两点P1(x1,y1,z1)、P2(x2,y2,z2)𝑃1(𝑥1,𝑦1,𝑧1)、𝑃2(𝑥2,𝑦2,𝑧2)的距离公式如下:
输入格式
每个输入文件包含多组数据。
输入文件的第一行,包含一个正整数T,代表该输入文件中所含的数据组数。
接下来是T组数据,每组数据的格式如下:
第一行包含三个正整数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 }
欢迎转帖 请保持文本完整并注明出处
技术博客 http://www.cnblogs.com/itdef/
B站算法视频题解
https://space.bilibili.com/18508846
qq 151435887
gitee https://gitee.com/def/
欢迎c c++ 算法爱好者 windows驱动爱好者 服务器程序员沟通交流
如果觉得不错,欢迎点赞,你的鼓励就是我的动力