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”(均不包含引号)。

数据范围

1n10001≤n≤1000,
1h,r1091≤h,r≤109,
T20T≤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 }
View Code

 

 

解法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 }
View Code

 

posted on 2019-05-12 20:29  itdef  阅读(226)  评论(0编辑  收藏  举报

导航