题目链接:http://poj.org/problem?id=2236
题目大意:
有n台损坏的电脑,现要将其逐台修复,且使其相互恢复通信功能。若两台电脑能相互通信,则有两种情况,一是他们之间的距离小于d,二是他们可以借助都可到达的第三台已修复的电脑。给出所有电脑的坐标位置,对其进行两种可能的操作,O x表示修复第x台,S x y表示判断x y之间能否通信,若能输出SUCCESS,否则输出FALL。
解题思路:判断图的连通性问题(并查集的简单应用)
首先,电脑之间若能通信,则大前提就是两台电脑都是维修过的,因此处理联通问题时,必须在已修好的电脑中进行。
由于通信可以传递,因此只要满足能够通信的条件,则新加入的电脑就可以借助这个小网络与其中任意一台通信,这就是使用并查集的关键条件
将满足距离关系的电脑并入一个集合中,此后每加入一台电脑都与前面加入的所有电脑做一次联通性的判断,即只要距离小于等于d就并入集合
代码如下:
Time:1391ms Memory:0.2MB Length: 1188
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 1110;
bool vis[maxn];
struct node
{
int head;
int x, y;
}c[maxn];
int n, d;
void init() //把每一个元素初始化为一个集合
{
for (int i = 1; i <= n; i++)
c[i].head = i; //初始化后每一个元素的父亲节点是它本身,每一个元素的祖先节点也是它本身
}
int find(int x) //查找一个元素所在的集合
{
return c[x].head == x ? x : find(c[x].head);
}
void Union(node c1, node c2) //合并c1,c2所在的两个集合
{
int a = find(c1.head);
int b = find(c2.head);
if(a!=b)
if((c1.x - c2.x)*(c1.x - c2.x) + (c1.y - c2.y)*(c1.y - c2.y)<=d*d)
c[b].head = a;
}
int main()
{
scanf("%d %d", &n, &d);
init();
memset(vis, false, sizeof(vis));
for (int i = 1; i <= n; i++)
scanf("%d %d", &c[i].x, &c[i].y);
char str[maxn];
while (~scanf("%s", str))
{
if (str[0] == 'O')
{
int x;
scanf("%d", &x);
vis[x] = true;
for (int i = 1; i <= n; i++)
if (i != x&&vis[i])
Union(c[i], c[x]);
}
else {
int x, y;
scanf("%d %d", &x, &y);
if (find(x) == find(y))
printf("SUCCESS\n");
else
printf("FAIL\n");
}
}
return 0;
}