http://poj.org/problem?id=2236
题意:给出一些电脑,它们目前都是损坏的状态,然后会依次修其中的一些,如果两台电脑都被修好了,并且它们之间的距离小于等于d,那么这两台电脑是可以沟通的。如果AB可以沟通,BC可以沟通,那么AC也是可以沟通的。现在查询两台电脑的时候,问它们是不是可以沟通的。
刚开始的时候,每一台电脑都是一个集合。每一个集合之内的电脑都可以互相沟通,不同集合内的电脑目前不可以沟通。某一台电脑A刚被修好的时候,要把其他已经维修好的电脑都枚举一遍,如果B距离符合要求,那么就说明这两台电脑之间可以沟通,那么A和B所在的集合中所有的电脑都可以沟通,A所在的集合和B所在的集合可以合并。处理好了以后,那么当前状态下,还是满足每一个集合内的电脑都可以互相沟通,不同集合内的电脑目前不可以沟通(比如两个不同集合中有CD,A在修好之前两者不能沟通,现在想要沟通一定也只能靠A作为桥梁,A连上C所在集合中任何一台电脑并且连上D所在集合中的任何一台电脑就可以,但是刚才A已经和每一台电脑都试过了,如果可以连上一定是会合并集合的,不会出现现在不同集合的情况。有点类似归纳法,到最后一步,还是满足的。
不要忘了初始化。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#include<string>
#define MAXN 1005
using namespace std;
int n, d, p, q, m;
char s[20];
int Par[MAXN], Rank[MAXN], re[MAXN], X[MAXN], Y[MAXN];
bool OK(int u, int v)
{
if ((X[u] - X[v]) * (X[u] - X[v]) + (Y[u] - Y[v]) * (Y[u] - Y[v]) <= d * d) return true;
else return false;
}
void init(int n)
{
for (int i = 0; i < n; i++)
{
Par[i] = i;
Rank[i] = 0;
}
}
int Find(int x)
{
if (Par[x] == x)
{
return x;
}
else
{
return Par[x] = Find(Par[x]); //路径压缩
}
}
void unite(int x, int y)
{
x = Find(x);
y = Find(y);
if (x == y) return;
if (Rank[x] < Rank[y])
{
Par[x] = y;
}
else
{
Par[y] = x;
if (Rank[x] == Rank[y]) Rank[x]++;
}
}
bool same(int x, int y)
{
return Find(x) == Find(y);
}
int main()
{
scanf("%d%d", &n, &d);
for (int i = 0; i < n; i++) scanf("%d%d", &X[i], &Y[i]);
memset(re, 0, sizeof(re));
init(n);
while (~scanf("%s", s))
{
if (s[0] == 'O')
{
scanf("%d", &m);
m--;
for (int i = 0; i < n; i++)
if (OK(m, i) && re[i] == 1 && m != i)
{
unite(m, i);
}
re[m] = 1;
}
if (s[0] == 'S')
{
scanf("%d%d", &p, &q);
p--;
q--;
if (same(p, q)) printf("SUCCESS\n");
else printf("FAIL\n");
}
}
return 0;
}