我天!哥们经过两个周的忙碌又重生了!
原题链接: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;
}