问题:Wireless Network POJ - 2236
南亚发生了一次地震。ACM (Asia Cooperated Medical 亚洲联合医疗队) 已经为膝上型电脑搭建了一个无线网络,但受到了一次不可预知的余震攻击,因此网络中的所有电脑都被破坏了。电脑被逐台修复,网络逐步恢复了工作。由于受到硬件的约束,每台电脑只能与距离它不超过 d 米的其它电脑直接通信。但每台电脑可被看作其它两台电脑的通信中转点,也就是说,如果电脑 A 和电脑 B 可以直接通信,或存在一台电脑 C 既可与 A 也可与 B 通信,那么电脑 A 和电脑 B 之间就能够通信。
在处理网络修复的过程中,工作人员们在任何一个时刻,可以执行两种操作:维修一台电脑,或测试两台电脑是否能够通信。请您找出全部的测试操作。
1. "O p" (1 <= p <= N),表示维护电脑 p 。
2. "S p q" (1 <= p, q <= N),表示测试电脑 p 和 q 是否能够通信。
输入不超过 300000 行。
4 1 0 1 0 2 0 3 0 4 O 1 O 2 O 4 S 1 4 O 3 S 1 4示例输出
FAIL SUCCESS
分析:
并查集的特点是,凡属于同一个集合的节点都具有同一性质,这里的“性质”比较好理解,就是同一个集合里面的节点(电脑)可以通信;初始化就是每一台电脑的根节点设置为自己,以后每出现一句修复指令,就修改根节点,根节点就是自己的一个节点要么是还没有修复的,要么就是已经修复了但不能与其他电脑通信(反正两种情况都不能通信)。修改根节点我们要先判断已经修复了的节点里面有没有和当前节点距离小于d的节点存在,存在的话就把两个节点合并,等到所有已经修复的节点都检查完了以后,再把当前处理节点记录为已经修复的节点,记录的方法就是把下标记录到vector中;当出现判断是否可通信的指令的时候,只要判断节点的根节点是否相同即可
#include<iostream>
#include<vector>
using namespace std;
int par[1010],Rank[1010];
vector<int> v;//存储已经修好了的电脑的下标
struct computer{
int x,y;
}comp[1010];
int find(int i){
if(i==par[i])return i;
return par[i]=find(par[i]);
}
void unite(int i,int j){
i=find(i);j=find(j);
if(Rank[i]>Rank[j]){
par[j]=i;return;
}
else{
par[i]=j;
if(Rank[j]==Rank[i]){
Rank[j]++;
}
return;
}
}
bool same(int i,int j){
i=find(i);j=find(j);
return i==j;
}
int main(){
int n,d;
cin>>n>>d;
for(int i=1;i<=n;i++){
par[i]=i;Rank[i]=1;
}
for(int i=1;i<=n;i++){
cin>>comp[i].x>>comp[i].y;
}
char ch;
while(cin>>ch){
if(ch=='O'){
int m;cin>>m;
int xm=comp[m].x,ym=comp[m].y;
for(int i=0;i<v.size();i++){
int xi=comp[v[i]].x,yi=comp[v[i]].y;
if((xi-xm)*(xi-xm)+(yi-ym)*(yi-ym)<=d*d)
unite(v[i],m);
}
v.push_back(m);
}
else if(ch=='S'){
int a,b;cin>>a>>b;
if(same(a,b))cout<<"SUCCESS"<<endl;
else cout<<"FAIL"<<endl;
}
}
return 0;
}