IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> P3958 [NOIP2017 提高组] 奶酪 简单题解 (并查集) -> 正文阅读

[数据结构与算法]P3958 [NOIP2017 提高组] 奶酪 简单题解 (并查集)

来写一篇题解。

关于并查集的基础内容请点击这里

题目传送门 洛谷P3598

思路

首先,我们可以将这些洞想象成一个点(就是球心)。题目询问的是小老鼠能否从奶酪最底下跑到奶酪最上面。意思就是,是否存在一个通道(连续很多个洞)从底面通向顶层。

这时候,就会自然而然的想到从底面的点开始搜索,能搜索到上面的点就输出Yes。(当然,搜索也是可以通过这一题的)

但我们应该思考:还有没有其他的方法?
当然有了不然就不会有下面的文字了

我们可以换一个角度想,对每一个能互相到达的点,我们都将它们染上一个颜色,最后只需要寻找顶部与底部有没有染成相同颜色的点就行了。

但我们肯定不会真的去“染色”,因为染色问题一般都用dfs(根据我现在的知识),用了染色,不就成了搜索了嘛。将思路转化一下,实际上,我们只需要对这些能互相联通的点打上相同的标记即可。

你想到了什么?自然而然的想到并查集啦。并查集对于能互相联通的点都会有一个相同的标记。这个时候问题就变成了求互联通的点的并查集,再对顶面和底面的点遍历,检查他们的祖先是否相同。

但是,这些点能否联通用什么来判断呢?
题目给了空间坐标系中的两点距离公式

d i s t ( P 1 , P 2 ) = ( x 1 ? x 2 ) 2 + ( y 1 ? y 2 ) 2 + ( z 1 ? z 2 ) 2 dist(P_1,P_2)=\sqrt{(x_1-x_2)^2+(y_1-y_2)^2+(z_1-z_2)^2} dist(P1?,P2?)=(x1??x2?)2+(y1??y2?)2+(z1??z2?)2 ?

实际上,我们只需判断这两个点的距离是否小于半径的两倍就可以啦。
当然,为了保证精度,我们只需比较它们的平方即可。即
d i s t ( P 1 , P 2 ) 2 = ( x 1 ? x 2 ) 2 + ( y 1 ? y 2 ) 2 + ( z 1 ? z 2 ) 2 dist (P_1,P_2)^2=(x_1-x_2)^2+(y_1-y_2)^2+(z_1-z_2)^2 dist(P1?,P2?)2=(x1??x2?)2+(y1??y2?)2+(z1??z2?)2

代码

下面上代码(有注释)

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cstring>
#include<vector>
#define ll long long
#define uint unsighed int 
#define ull unsighed long long
using namespace std;
const ll N=5e5+10;
const ll Z=1e9+7;

ll f[N]; 
ll f1[N],f2[N],cnt1,cnt2; //f1记录在顶面的点,f2记录在底面的点
ll x[N],y[N],z[N]; //存坐标


void init(int n) //初始化
{
	cnt1=cnt2=0;
	for(int i=1;i<=n;++i) f[i]=i;
}
	
int find(int x) //并查集与路径压缩
{
	if(x==f[x]) return x;
	return f[x]=find(f[x]);
}

ll ksm(ll base,ll p)  //听说pow不是很好用?于是来了一个快速幂
{
	ll ans=1;
	while(p)
	{
		if(p&1) ans*=base;
		base*=base;
		p>>=1;
	}
	return ans;
}


int main()
{
	//ios::sync_with_stdio(false);
	ll T;cin>>T;
	while(T--)
	{
		ll n,h,r;
		cin>>n>>h>>r;
		init(n);
		for(ll i=1;i<=n;++i)
		{
			cin>>x[i]>>y[i]>>z[i];
			if(z[i]+r>=h) f1[++cnt1]=i; //f1记录在顶面的点
			if(z[i]-r<=0) f2[++cnt2]=i; //f2记录在底面的点
		}
		for(ll i=1;i<=n;++i)
		{
			for(ll j=i+1;j<=n;++j)
			{
				ll fx=find(i);ll fy=find(j);
				if(fx==fy) continue; //如果两个点已经相通,跳过
				ll dist=ksm(x[i]-x[j],2)+ksm(y[i]-y[j],2)+ksm(z[i]-z[j],2); //计算距离
				ll rdist=r*r*4; //两点间的半径
				if(dist<=rdist) f[fx]=fy;
			}
		}
		bool flag=0;
		//cout<<cnt1<<" "<<cnt2<<endl;
		for(ll i=1;i<=cnt1;++i)
		{
			for(ll j=1;j<=cnt2;++j)
			{
				if(find(f1[i])==find(f2[j]))
				{
					flag=1; 
					break;
				}
			}
		}
		if(flag) cout<<"Yes"<<endl;
		else cout<<"No"<<endl;
	}
 	return 0;		
}

类似的问题,也可以用并查集实现。

其他方法(搜索)

听说两种搜索方法都可以用。可以考虑链式前向星建图,再进行dfs和bfs等。就不放代码了。(因为我还没写)

代码中值得注意的地方

  • 注意f数组的初始化
  • 重新读入下一轮数据时,将f1,f2数组的计数变量重新初始化。
  • 没了
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-07-28 00:18:38  更:2021-07-28 00:18:55 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/27 10:13:23-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计