B - Wireless Network POJ - 2236 简单易懂的并查集(路径压缩,按秩合并)
题意:在一个平面中,有n台电脑,但是此时所有的电脑都是坏的,给出每台电脑的坐标(x,y)和一个距离d
如果电脑是好的,并且电脑之间的距离小于d,那么这两台电脑就可以联通,电脑可以借助电脑联通,也就是说,如果
a--b b--c 那么可以认为 a--c 。现在给出两种操作, ‘O’ 表示修理某一台电脑,‘S’表示查询 两台电脑是否联通
是 则输出“SUCCESS” 否则输出“FAIL”
思路: 很明显的一个并查集题目,如果两台电脑之间的距离小于d,就认为他们直接有联系,如果两台电脑都是修好的,并且有联系,就认为他们可以联通,把这两台电脑合并集合。查询就直接判断两台电脑是否在一个集合中即可。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstring> #include<cstdio> #include<queue> using namespace std; int n,D; int par[1005],rk[1005],link[1005][1005],vis[1005]//link记录联系,vis记录是否被修好; int X[1005],Y[1005];//记录坐标 void init()//初始化 { for(int i=1;i<=n;i++){ par[i]=i; rk[i]=0; } } int Find(int x)//查找(最好写成非递归的查找方式) { while(x!=par[x]) x=par[x]; return x; } void unite(int x,int y)//合并 { x=Find(x); y=Find(y); if(x==y) return ; if(rk[x]<rk[y]) par[x]=y; else{ par[y]=x; if(rk[x]==rk[y]) rk[x]++; } } bool same(int x,int y)//判断是否处于一个集合 { return Find(x)==Find(y); } int main() { memset(link,0,sizeof link); memset(vis,0,sizeof vis); scanf("%d%d",&n,&D); init(); for(int i=1;i<=n;i++) scanf("%d%d",&X[i],&Y[i]); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++){ if((X[i]-X[j])*(X[i]-X[j])+(Y[i]-Y[j])*(Y[i]-Y[j])<=D*D){//建立联系 link[i][j]=1; } } char ch[2]; int a,b; while(~scanf("%s",ch)){ if(ch[0]=='O'){//修好一台电脑,就判断此台电脑是否可以和其他电脑联通 scanf("%d",&a); vis[a]=1; for(int i=1;i<=n;i++) if(vis[i]==true&&i!=a&&link[a][i]) unite(a,i) ; } else if(ch[0]=='S'){ scanf("%d%d",&a,&b); if(same(a,b)) printf("SUCCESS\n"); else printf("FAIL\n"); } } return 0; }