题目描述:
http://poj.org/problem?id=2236
中文大意:
东南亚发生地震,工作人员进行网络修复。
由于硬件限制,每台计算机只能与 (0,d] 范围内的计算机进行通信,但却可以充当中介,即如果计算机 C 可以与计算机 A 和计算机 B 进行通信,则计算机 A 和计算机 B 可以进行通信。
在修复网络的过程中,工作人员可以随时执行两种操作:修复一台计算机、测试两台计算机是否可以通信。
我们的工作是回答所有测试操作。
思路:
一个计算机网络就是一个集合。
每修复一台计算机,便尝试将它与 (0,d] 范围内的所有已经被修复的计算机进行连接。
两台计算机可以通讯的前提条件是:在同一个集合中,且均已被修复。
代码:
#include<iostream>
#include<cstring>
#include<algorithm>
#include<math.h>
using namespace std;
//记录各节点的位置信息
struct node{
int x,y;
}pos[1002];
int sets[1002];//各节点的所属集
int height[1002];//各集合的树高
bool repaired[1002] = {false};//是否被修理
int n,d;
//初始化,各节点属于独立的集合
void init(){
for(int i=1;i<=n;i++){
sets[i] = i;
height[i] = 1;
}
}
//查询节点 x 的所属集
int find(int x){
//寻找根节点
int root = x;
while(root != sets[root]){
root = sets[root];
}
//路径压缩:将路径上节点的所属集修改为根节点
int i = x;
while(sets[i] != root){
int j = sets[i];
sets[i] = root;
i = j;
}
return root;
}
//合并
void union_set(int x, int y){
//寻找节点 x 的所属集
x = find(x);
//寻找节点 y 的所属集
y = find(y);
//若两个节点的所属集树高相同,则将 x 的所属集并到 y 的所属集
if(height[x] == height[y]){
sets[x] = y;
height[y]++;
}//否则,将矮树并到高树,高树的树高保持不变
else if(height[x] > height[y]){
sets[y] = x;
}
else{
sets[x] = y;
}
}
//计算两个节点之间的距离
int cal_dis(int x, int y){
int dis_x = pos[x].x - pos[y].x;
int dis_y = pos[x].y - pos[y].y;
return dis_x*dis_x + dis_y*dis_y;
}
int main(){
scanf("%d %d", &n, &d);
init();
for(int i=1;i<=n;i++){
scanf("%d %d", &pos[i].x, &pos[i].y);
}
char c;
int x,y;
getchar();//scanf("%c", &c) 会读入回车
while(~scanf("%c", &c)){
if(c == 'O'){
scanf("%d", &x);
repaired[x] = true;
//将节点 x 合并到 (0,d] 范围内的集合中
for(int i=1;i<=n;i++){
if(i == x || !repaired[i]){
continue;
}
int dis = cal_dis(x, i);
if(dis <= d*d){
union_set(x, i);
}
}
}
else if(c == 'S'){
scanf("%d %d", &x, &y);
//两台计算机均被修理,且在同一个通讯网络中
if(repaired[x] && repaired[y] && find(x) == find(y)){
printf("SUCCESS
");
}
else{
printf("FAIL
");
}
}
getchar();
}
}