POJ 2236 Wireless Network

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


Wireless Network

Time Limit: 10000MS
Memory Limit: 65536K
Total Submissions: 19684
Accepted: 8252

Description

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.

Input

The first line contains two integers N and d (1 <= N <= 1001, 0 <= d <= 20000). Here N is the number of computers, which are numbered from 1 to N, and D is the maximum distance two computers can communicate directly. In the next N lines, each contains two integers xi, yi (0 <= xi, yi <= 10000), which is the coordinate of N computers. From the (N+1)-th line to the end of input, there are operations, which are carried out one by one. Each line contains an operation in one of following two formats:
1. "O p" (1 <= p <= N), which means repairing computer p.
2. "S p q" (1 <= p, q <= N), which means testing whether computer p and q can communicate. 

The input will not exceed 300000 lines.

Output

For each Testing operation, print "SUCCESS" if the two computers can communicate, or "FAIL" if not.

Sample Input

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


Sample Output

FAIL
SUCCESS


Source


大意——现在有n台损坏的电脑,目前可以一个一个地进行维修。由于硬件的限制,修好了的电脑想要直接相连,那么它们之间的距离必须小于dist。但是如果A与C连接,C与B又连接,那么A与B就间接连接。在修电脑的过程中,工作者随时可以进行两种操作,修电脑或者是测试两台电脑是否已经连接。你的任务是对于每一次测试,如果成功连接,输出SUCCESS,否则输出FAIL。

思路——经过题目分析,发现这是一道裸的并查集的题。查询两台电脑是否连接就是并查集的查询操作,而将两台电脑连接起来就是合并操作。其中合并操作可以按集合规模进行,而查询操作过程中可以进行路径压缩,路径压缩对于性能是至关重要的。当每次我们修好一台电脑后就可以将它与所能连接到的修好的电脑给连接起来。

复杂度分析——时间复杂度:O(n+n*ɑ(n)),空间复杂度:O(n),ɑ(n)阿克尔曼反函数,n在一定范围内可以认为是常数

附上AC代码:

#include <iostream>
#include <cstdio>
#include <string>
#include <cmath>
#include <iomanip>
#include <ctime>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
#include <set>
#include <map>
//#pragma comment(linker, "/STACK:102400000, 102400000")
using namespace std;
typedef unsigned int li;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const double pi = acos(-1.0);
const double e = exp(1.0);
const double eps = 1e-8;
const int maxn = 1005;
int father[maxn]; // 存储父节点
char str[5]; // 键入命令
int n, dist; // 电脑台数以及连接距离限制
struct point
{ // 存储电脑坐标及其状态(0表示未修好,1表示修好)
	int x, y;
	bool flag;
} com[maxn];

inline int square(int x); // 计算平方值
inline int distan(point a, point b); // 计算电脑距离的平方
int find(int x); // 查找父节点并路径压缩
void com_union(int x, int y); // 合并能连接到的电脑

int main()
{
	ios::sync_with_stdio(false);
	int x, y;
	while (~scanf("%d%d", &n, &dist))
	{
		memset(father, -1, sizeof(father)); // 初始化
		dist *= dist; // 距离限制的平方
		for (int i=1; i<=n; i++)
		{
			scanf("%d%d", &com[i].x, &com[i].y);
			com[i].flag = 0; // 初始化
		}
		while (~scanf("%s%d", str, &x))
		{
			if (str[0] == 'O')
			{
				com[x].flag = 1;
				for (int i=1; i<=n; i++) // 找出能连接的电脑
					if (i!=x && com[i].flag &&
						distan(com[x], com[i])<=dist)
						com_union(x, i);
			}
			else
			{
				scanf("%d", &y);
				x = find(x);
				y = find(y); // 找出父节点
				printf(x==y ? "SUCCESS\n" : "FAIL\n"); // 父节点相等,则表明连接好了
			}
		}
	}
	return 0;
}

inline int square(int x)
{
	return (x*x);
}

inline int distan(point a, point b)
{
	return square(a.x-b.x)+square(a.y-b.y);
}

int find(int x)
{
	if (father[x] < 0)
		return x;
	return father[x] = find(father[x]); // 此处即为路径压缩
}

void com_union(int x, int y)
{ // 启发式合并,按规模进行
	x = find(x);
	y = find(y);
	if (x == y)
		return ;
	if (father[x] > father[y])
	{ // 根节点的父节点为负数,绝对值为规模大小
		father[y] += father[x];
		father[x] = y;
	}
	else
	{
		father[x] += father[y];
		father[y] = x;
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值