我天!哥们经过两个周的忙碌又重生了!
原题链接:528. 奶酪 - AcWing题库
本题注意点:
- 注意几个边界值,如果说没有球连接顶部或者底部,老鼠是不可能上来的,直接say no!
- 要利用公式判断两个球是相切or相交 ,相离是没有可能的,也是直接say no!
- 主要距离公式:
d i s t = ( x 1 − x 2 ) 2 + ( y 1 − y 2 ) 2 + ( z 1 − z 2 ) 2 {dist}= \sqrt{ (x_1 - x_2)^2 + (y_1 - y_2)^2 + (z_1 - z_2)^2 } dist=(x1−x2)2+(y1−y2)2+(z1−z2)2
看题目的大意,有点像查找最小连通图的影子,现在先用并查集解决问题:
解法1:并查集
时间复杂度: T ( n 2 ) T(n^2) T(n2),运行时间753ms
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1010;int t;
int p[N];
int n,h,r;struct Spot{ll x,y,z;
}a[N];int find(int x){if(p[x]!=x) {p[x]=find(p[x]);}return p[x];
}int judge(ll x1,ll x2,ll y1,ll y2,ll z1,ll z2,ll r)//判断两个空洞是否有交集
{return (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)+(z1-z2)*(z1-z2)<=(4*r*r)?1:0;
}void merge(int x,int y){p[find(x)]=find(y);
}
int main()
{scanf("%d",&t);while(t--){scanf("%d%d%d",&n,&h,&r);for(int i=1;i<=n;i++){a[i].x=a[i].y=a[i].z=0; //一定要清空数组p[i]=i; //并查集初始化}//0代表奶酪底部,1001代表奶酪顶部p[0]=0,p[1001]=1001;for(int i=1;i<=n;i++){cin>>a[i].x>>a[i].y>>a[i].z;if(a[i].z-r<=0){ //空洞最低点在奶酪外或与奶酪相切,与底部合并merge(i,0);}if(a[i].z+r>=h){//同理,最高点在奶酪外或相切,与顶部合并merge(i,1001);}}for(int i=1;i<=n;i++){for(int j=i+1;j<=n;j++){if(judge(a[i].x,a[j].x,a[i].y,a[j].y,a[i].z,a[j].z,r)){//有交集就合并merge(i,j);}}}if(find(0)==find(1001)) printf("Yes\n");//底部和顶部相连通即根节点相同else printf("No\n");}return 0;
}
解法2:dfs(深度优先搜索)
主要思想:用空间换取时间
AC 代码:
//利用dfs
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1010;int t;
int vis[N];
int found; //用于插眼
int n,h,r;struct Spot{ll x,y,z;
}a[N];int judge(ll x1,ll x2,ll y1,ll y2,ll z1,ll z2,ll r){return (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)+(z1-z2)*(z1-z2)<=(4*r*r)?1:0;
}
void dfs(int m){if(a[m].z+r>=h){//递归出口,即搜到顶端found=1;return;}vis[m]=1;//标记走过for(int i=1;i<=n;i++){if(!vis[i]&&judge(a[i].x,a[m].x,a[i].y,a[m].y,a[i].z,a[m].z,r)){//没有访问且两个空洞有交集,继续搜索dfs(i);}}
}
int main(){cin>>t;while(t--){found=0; //初始化for(int i=1;i<=n;i++){a[i].x=a[i].y=a[i].z=0; //一定要清空数组}memset(vis,0,sizeof(vis));cin>>n>>h>>r;for(int i=1;i<=n;i++){cin>>a[i].x>>a[i].y>>a[i].z;}for(int i=1;i<=n;i++){if(!vis[i]&&a[i].z<=r){//没有访问过并且和底部相连通,即dfs入口dfs(i);}if(found==1)break;}if(found==1) printf("Yes\n");else printf("No\n");}return 0;
}