http://poj.org/problem?id=2236
由于发生了地震,有关组织组把一圈电脑一个无线网,但是由于余震的破坏,所有的电脑都被损坏,随着电脑一个个被修好,无线网也逐步恢复工作,但是由于硬件的限制,一台电脑和另一台电脑能够相连当他们之间的距离小于d,或者还有一台电脑当中介,分别与两台电脑相连。
在修复的过程中,工作者会有两种操作,修复电脑和询问电脑a和电脑b是否相连。当询问的时候输出答案。
因为输入数据很大,需要快速判断电脑a和电脑b相连,所以自然想到用并查集。
初始时候 全部电脑都是损坏的,那么每修复一次,就需要把与当前电脑距离小于d并且已经修复的电脑连接起来,询问的时候直接判断即可。
1 #include<cstdio> 2 #include<cmath> 3 #include<cstring> 4 using namespace std; 5 const int maxn = 1010; 6 struct node 7 { 8 int x,y; 9 }p[maxn]; 10 int par[maxn],flag[maxn]; //作为是否修复的标记 11 int n; 12 double dis[maxn][maxn]; //存储两点之间的距离 13 double d; 14 void init() 15 { 16 for(int i=1;i<=n;i++) par[i]=i; 17 } 18 19 int find(int x) 20 { 21 return x==par[x]?x:par[x]=find(par[x]); 22 } 23 24 void unite(int x,int y) 25 { 26 x=find(x); 27 y=find(y); 28 if(x!=y) 29 par[x]=y; 30 } 31 32 void distance(int a,int b) 33 { 34 dis[a][b]=dis[b][a]=sqrt(1.0*(p[a].x-p[b].x)*(p[a].x-p[b].x)+1.0*(p[a].y-p[b].y)*(p[a].y-p[b].y)); 35 } 36 37 void solve(int x) 38 { 39 for(int i=1;i<=n;i++) 40 { 41 if(i!=x&&flag[i]&&dis[x][i]<=d) 42 unite(x,i); 43 } 44 } 45 46 int main() 47 { 48 //freopen("a.txt","r",stdin); 49 scanf("%d%lf",&n,&d); 50 init(); 51 memset(flag,0,sizeof(flag)); 52 memset(dis,0,sizeof(dis)); 53 for(int i=1;i<=n;i++) 54 scanf("%d%d",&p[i].x,&p[i].y); 55 for(int i=1;i<=n;i++) //预处理所有两点之间的距离 56 for(int j=i+1;j<=n;j++) 57 distance(i,j); 58 char s[2]; 59 int a,b; 60 while(~scanf("%s",s)) 61 { 62 if(s[0]=='O') 63 { 64 scanf("%d",&a); 65 flag[a]=1; 66 solve(a); 67 } 68 else if(s[0]=='S') 69 { 70 scanf("%d%d",&a,&b); 71 if(find(a)==find(b)) printf("SUCCESS "); 72 else printf("FAIL "); 73 } 74 } 75 return 0; 76 }
http://poj.org/problem?id=1611
在大学里有n个学生(0-n-1)和m个社团,每个学生可以加多个社团,但是因为SARS的流行,学校需要统计出有多少病毒携带者,如果一个社团有一个携带者,那么整个社团都是 病毒携带者,现在已知0号学生是携带者,给出m个社团的信息,求出有多少人感染。
基础的并查集,只要增加一个rank[]用来统计每一个组的人数,这样在unite的时候累加合并过来的人数,最后输出0号所在的组的人数。
1 #include <cstdio> 2 #include <queue> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 const int maxn = 30010; 7 int par[maxn],rank[maxn]; 8 9 void init(int n) 10 { 11 for(int i=0;i<n;i++) 12 { 13 par[i]=i; 14 rank[i]=1; 15 } 16 } 17 18 int find(int x) 19 { 20 return x==par[x]?x:par[x]=find(par[x]); 21 } 22 23 void unite(int x,int y) 24 { 25 x=find(x); 26 y=find(y); 27 if(x!=y) 28 { 29 par[x]=y; 30 rank[y]+=rank[x]; 31 } 32 } 33 34 int main() 35 { 36 int n,m,k,a,b; 37 while(~scanf("%d%d",&n,&m)) 38 { 39 if(n==0&&m==0) break; 40 init(n); 41 for(int i=0;i<m;i++) 42 { 43 scanf("%d",&k); 44 for(int j=0;j<k;j++) 45 { 46 scanf("%d",&a); 47 if(j==0) 48 { 49 b=a; 50 } 51 else unite(a,b); 52 } 53 } 54 printf("%d ",rank[find(0)]); 55 } 56 return 0; 57 }
http://poj.org/problem?id=2524
n个学生,每个学生都只有一种信仰,给出m条关系,统计最多有多少种信仰。
简单并查集,读入关系后合并即可。
1 #include <cstdio> 2 const int maxn = 50010; 3 int n,count,par[maxn]; 4 5 void init(int n) 6 { 7 for(int i=1;i<=n;i++) 8 { 9 par[i]=i; 10 } 11 } 12 13 int find(int x) 14 { 15 return x==par[x]?x:par[x]=find(par[x]); 16 } 17 18 void unite(int x,int y) 19 { 20 x=find(x); 21 y=find(y); 22 if(x!=y) 23 { 24 par[x]=y; 25 count--; 26 } 27 } 28 29 int main() 30 { 31 int m,a,b,j=1; 32 while(~scanf("%d%d",&n,&m)) 33 { 34 if(n==0&&m==0) break; 35 count=n; 36 init(n); 37 for(int i=0;i<m;i++) 38 { 39 scanf("%d%d",&a,&b); 40 unite(a,b); 41 } 42 printf("Case %d: %d ",j++,count); 43 } 44 return 0; 45 }