POJ-2236 :Wireless Network (并查集)超详解析

首先了解一下题意,题意很清楚,即使使用网页自带翻译也完全能看懂

题目:

An earthquake takes place in Southeast Asia. The ACM (Asia Cooperated Medical team) have set up a wireless network with the lap computers, but an unexpected aftershock attacked, all computers in the network were all broken. The computers are repaired one by one, and the network gradually began to work again. Because of the hardware restricts, each computer can only directly communicate with the computers that are not farther than d meters from it. But every computer can be regarded as the intermediary of the communication between two other computers, that is to say computer A and computer B can communicate if computer A and computer B can communicate directly or there is a computer C that can communicate with both A and B.

In the process of repairing the network, workers can take two kinds of operations at every moment, repairing a computer, or testing if two computers can communicate. Your job is to answer all the testing operations.

题目意思:

有一个计算机网络的所有线路都坏了,网络中有n台计算机,现在你可以做两种操作,修理(O)和检测两台计算机是否连通(S),只有修理好的计算机才能连通。连通有个规则,两台计算机的距离不能超过给定的最大距离D(一开始会给你n台计算机的坐标)。检测的时候输出两台计算机是否能连通。

输入:

4 1
0 1
0 2
0 3
0 4
O 1
O 2
O 4
S 1 4
O 3
S 1 4


输出:

FAIL
SUCCESS
 

思路:当我看到这个题的时候,很容易想到了并查集,初步思路很快就形成了:先利用结构体储存一个点的x和y(对坐标类点的常用方法),于是我们就能得到n个点,由题可知:刚开始所有电脑都损坏,所以我们暂时不能连线任何一台电脑,我们需要再每次的维修新电脑的操作中去尝试与已维修的电脑建立联系

那么总体结构就出来了:

1.存点

2.进行操作

(1)如果是维修指令:那么对此电脑标记已维修(方便后来者尝试建立联系),然后直接遍历一次所有的点,找到已维修并且完全符合要求的点,进行合并(归到同一个父亲)。

(2)如果是查询指令,只需要查现在这两个点的父亲是不是一样就好了

(这是一个坐标类型的图,那么就意味着最大可能会有n*n条边+循环嵌套,自然实现过程中大概率会消耗大量的时间,然而看到n的范围只有1k,而时间限制为1w那么很有可能就是使用并查集了。)

那么直接上代码详解:

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;

const int N=1e3+50;
//题目范围

int n;
double d;
//基本定义

int pre[N];
int vis[N];
//父亲数组、标记数组

struct Node{
	int x,y;
}edge[N];
//简单的结构体,简单暴力的将点给装好

void init(){
	for(int i=1;i<=n;i++){
		pre[i]=i;
	}
}
//初始化父亲结点,刚开始每台电脑都是独立不连通的,父亲为自己

int find(int x){
	if(x==pre[x])return x;
	else return pre[x]=find(pre[x]);
}
//查找函数,如果找到一个关系树的根(祖宗)就返回
//如果不是,那么顺着父亲关系一直往上找到祖宗
//过程中要更新你的父亲结点(最后从祖宗递归回来就装的祖宗了,方便查找)

void meary(int a,int b){
	double D=(edge[a].x-edge[b].x)*(edge[a].x-edge[b].x)+(edge[a].y-edge[b].y)*(edge[a].y-edge[b].y);
//算两点的距离公式
//sqrt和pow函数貌似poj不支持还是怎么的
//反正有问题,直接做平方的比较,这样C++,G++都拿捏
//下面就是很常规的合并,将两人其中一人的父亲结点赋值为另一个人的父亲节点
	int dx=find(a);
	int dy=find(b);
	if(dx!=dy&&d*d>=D){
		pre[dx]=dy;
	}
}
//结合函数

int main(){
	cin >> n >> d;
	init();
	for(int i=1;i<=n;i++){
		cin >> edge[i].x >> edge[i].y;//输入点的x和y
	}
	char c;
	int a,b;
	while(cin >> c){
//开始操作

		if(c=='O'){
//维修操作

			cin >> a;
			vis[a]=1;
//vis标记电脑已经修好

			for(int i=1;i<=n;i++){
//遍历点,修好且满足要求就合并(部分要求判别在合并函数中)

				if(vis[i]){
					meary(a,i);
				}
			}
		}
		else{
//查询操作

			cin >> a >> b;
			if(find(a)==find(b)){
//是一家人就ok了!

				cout << "SUCCESS" << endl;
			}
			else{
//不是就G

				cout << "FAIL" << endl;
			}
		}
	}
	return 0;
} 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值