POJ_2236(Wireless Network)

题目链接:http://poj.org/problem?id=2236


首先先说一下一个坑点,,现在还不知道为啥,一开始是TLE,我找了很久,没有发现错误,后来想到以前poj的尿性,想到可能是一组输入,于是我就改成了一组输入,莫名其妙就ac了,按道理来说应该即使只有一组输入,我写出while(scanf....)也会只读入一组输入的,不应该出现TLE情况的!


这道题题意就是有多个通讯点,在他们好用和相互之间距离小于等于d的情况下,可以相互通讯!而一开始全部损坏了,经过一系列操作,有修复和查询问你查询后是否能够通讯的结果!

首先我们可以分析出来,有300000行,每一次暴力你都需要遍历原来已经修复好的通讯点,0(N2)的复杂度是肯定不能过的!那么就需要用到并查集!在这道题中,哪些条件适用于并查集的处理!


并查集其实就是集合的合并和查询!!处理只有合并!那么在这道题的输入中,每次都会输入修复的点,其实就是告诉我们在合并修复点的集合!而后面的查询操作其实也就是不正是可以看出集合的查询吗!我们修复了的点满足了距离要求的话,我们就可以给它加入到集合中取,通过路径压缩,后面的查询是0(1)级别的,时间上能够通过!下面画一下图看看什么是路径压缩!

POJ_2236(Wireless Network)_第1张图片


就是说通过路径压缩后,在一个findd函数后,集合中始终只会有俩层,那么你下次查询的时候,一下子就能找到父亲结点!!


代码如下:

#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
#include <stack>
#include <queue>
#include <map>
#include <vector>
#include <cmath>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
const int maxn = 1111;
int pre[maxn];
int vis[maxn];
void init()
{
	for (int i = 0; i<maxn; i++)
		pre[i] = i;                         //自己的父亲是自己,孤立一点
}
int findd(int n)
{
	if (n == pre[n])
		return n;
	else
		return pre[n] = findd(pre[n]);
}
void unionn(int u, int v)                     //整个集合中始终只有一个父亲
{
	int fu = findd(u);
	int fv = findd(v);
	pre[fu] = fv;
}
struct node
{
	int x, y;
	node() {}
	node(int x, int y) :x(x), y(y) {}
}node1[maxn];
int d;
bool distance1(node a, node b)
{
	if ((a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y) <= d*d)
		return true;
	else
		return false;
}
int main(void)
{
	//freopen("in.txt", "r", stdin);                   //你需要记录哪些是已经修复好了的
	int N, i, j;
	//while (scanf("%d%d", &N, &d))                    //这里无法理解,我变成了一组输入就过了,多组输入就过不了
	//{
		scanf("%d%d", &N, &d);
		init();
		for (i = 1; i<=N; i++)
		{
			int x, y;
			scanf("%d%d", &x, &y);
			node1[i] = node(x, y);
		}
		string op;
		int xx, yy;
		memset(vis, 0, sizeof(vis));
		while (cin >> op)
		{
			if (op[0] == 'O')                                                    
			{
				scanf("%d", &xx);                                                  //你要知道,哪些结点是已经修复好的,所以用一个数组来维护
				vis[xx] = 1;													   //vis来记录哪些结点是已经修复好了的,用一个数组来维护
				for (i = 1; i <= N; i++)
				{
					if (vis[i]&&distance1(node1[i],node1[xx])&&i!=xx)                     //找原来已经修复好了,并且能够满足由于硬件条件距离限制的通讯设备
					{
						unionn(i, xx);
					}
				}
			}
			else
			{
				scanf("%d%d", &xx, &yy);
				if (findd(xx) == findd(yy))
					printf("SUCCESS\n");
				else
					printf("FAIL\n");
			}
		}
	//}
	return 0;
}

你可能感兴趣的:(并查集,路径压缩)