其他分享
首页 > 其他分享> > 题解 Luogu P3958 【奶酪】

题解 Luogu P3958 【奶酪】

作者:互联网

一道并查集入门好题

博客食用风味更佳

step 0xff:本题解的起源

初学树形数据结构(并查集)时考试中出现了此题,后来又在随机跳题和智颓中见到此题,顺手A了凑数。看看题解拓宽思路,发现好像没有与我相同的思路,便试着发一篇题解……

step 0x00:题义简叙

一只老鼠想从奶酪下面通过奶酪中的洞穿行到奶酪上面,每个奶酪的洞为完美球形(怎么发酵出来的)。当任意两个洞相交或相切时,这只老鼠便可以在这两个洞中来往(好奇相切是这么穿过去的)。问:老鼠能不能从奶酪底经过奶酪到奶酪上面。

step 0x01:数学模型初构造

把每一个洞看作一个节点,有一边\(e=(u,v)\)当且仅当洞\(u\)与洞\(v\)相交或相切。问是否有一条路径能从一个接触奶酪底面的洞穿到一个接触奶酪顶面的洞。

step 0x02:数学模型改造

注意到题中给出一公式:

空间内两点\(P_1(x_1,y_1,z_1)\)、\(P_2(x_2,y_2,z_2)\)的距离公式如下:

\[\mathrm{dist}(P_1,P_2)=\sqrt{(x_1-x_2)^2+(y_1-y_2)^2+(z_1-z_2)^2} \]

有什么用呢?

显然,判断两洞(球)是否联通在于(\(\color{red}\texttt{两球心间距离}\)\(\le\!2r\)。)

我看到很多dalao在构建出数学模型后,使出浑身解数来判断顶面与底面是否联通。

本蒟蒻想到一个方法——把顶面与底面看作两个超大型的洞(节点)“天”和“地”,则判断顶面与底面是否联通转化为:天节点是否与地节点联通。见下图。

画技不好,请见谅。

step 0x03:核心算法

上段说到,问题转化为判断天地节点是否联通。

说到判断两元素是否连通,你想到了什么呢?

反正本蒟蒻只想到了\(\text{DFS}\)和并查集。

个人不太喜欢\(\text{DFS}\),而且讨厌建图,于是用了并查集。每输入一个节点的信息,就遍历所有已知节点,如果联通就合并两点所在的集合。全部输入完后,每一个集合就代表一个联通块,判断天地

step 0x04:放代码

批曰「「具体实现见代码及注释」」

温馨提示:代码设了锅,如有抄的意向,请自行@管理员【滑稽】。

#include<bits/stdc++.h>//万能头文件
using namespace std;//命名空间
#define tj//考试用缺省源,懒得删
#define int long long//80分锅在此,不开longlong见祖宗。
int f[10010],x[10010],y[10010],z[10010];//并查集数组,球心坐标
int get(int x){//get_root 求根函数
	return f[x]==-1?x:f[x]=get(f[x]);//路径压缩
}
void hb(int a,int b){//合并
	a=get(a),b=get(b);
	if(a!=b)f[a]=b;	//wtcl,只会这样朴素算法
}
bool pd(int ax,int ay,int az,int bx,int by,int bz,int r){//已知两点坐标与球的半径,判断是否联通
	ax-=bx,ay-=by,az-=bz;
	if(r*2>=sqrt((long long)ax*ax+(long long)ay*ay+(long long)az*az))return 1;//80分注意不开longlong见祖宗!
	else return 0;//套公式
}
int main(){//主函数
#ifdef tj
	freopen(".in","r",stdin);
	freopen(".out","w",stdout);//考试用缺省源
#endif
	int T;
	scanf("%d",&T);
	while(T--){//多组数据
		int n,h,r;
		memset(f,-1,sizeof(f));//数组初始化
		scanf("%d%d%d",&n,&h,&r);//数据
		for(register int i=1;i<=n;i++){
			scanf("%d%d%d",x+i,y+i,z+i);//点坐标
			if(h<=z[i]+r)hb(n+1,i);//通天
			if(z[i]-r<=0)hb(0,i);//接地气
			for(register int j=1;j<i;j++)//n方判联通
				if(pd(x[i],y[i],z[i],x[j],y[j],z[j],r))
					hb(i,j);
		}
		if(get(0)==get(n+1))puts("Yes");//天地合一的情况
		else puts("No");//天地链接被断开的情况
	}
	return 0;//愉快のend
}

蒟蒻码字不易,各位看官不点个赞再走吗……

标签:联通,int,题解,奶酪,step,long,P3958,Luogu,节点
来源: https://www.cnblogs.com/Diwanul/p/SolutionLuoguP3958.html