标签:
推荐学习地址:http://www.cnblogs.com/cyjb/p/UnionFindSets.html
简单:
1 #include<cstdio> 2 const int N=1001; 3 int f[N]; 4 void init(int n){ 5 for(int i=1;i<=n;++i) 6 f[i]=i; 7 } 8 int fin(int x){ 9 if(x!=f[x])f[x]=fin(f[x]); 10 return f[x]; 11 } 12 void uni(int x,int y){ 13 if((x=fin(x))==(y=fin(y)))return; 14 else f[x]=y; 15 } 16 int main(){ 17 int t,i,n,m,a,b,ans; 18 scanf("%d",&t); 19 while(t--){ 20 scanf("%d%d",&n,&m); 21 init(n); 22 while(m--){ 23 scanf("%d%d",&a,&b); 24 uni(a,b); 25 } 26 ans=0; 27 for(i=1;i<=n;++i) 28 if(f[i]==i) 29 ans++; 30 printf("%d\n",ans); 31 } 32 }
hdu1232 畅通工程:新手必秒
1 #include<cstdio> 2 const int N=1001; 3 int f[N]; 4 void init(int n){ 5 for(int i=1;i<=n;++i) 6 f[i]=i; 7 } 8 int fin(int x){ 9 if(x!=f[x])f[x]=fin(f[x]); 10 return f[x]; 11 } 12 void uni(int x,int y){ 13 if((x=fin(x))==(y=fin(y)))return; 14 else f[x]=y; 15 } 16 int main(){ 17 int i,n,m,a,b,ans; 18 while(scanf("%d%d",&n,&m),n){ 19 init(n); 20 while(m--){ 21 scanf("%d%d",&a,&b); 22 uni(a,b); 23 } 24 ans=0; 25 for(i=1;i<=n;++i) 26 if(f[i]==i) 27 ans++; 28 printf("%d\n",ans-1); 29 } 30 }
hdu1272 小希的迷宫:判断连通无环图。判连通只需判断根节点数为1,判环只需判断输入边的两个点是否有公共父节点。
1 #include<cstdio> 2 const int N=100001; 3 int f[N]; 4 int v[N];//标记结点是否在图中 5 int t;//判断是否有回路 6 void init(){ 7 for(int i=1;i<N;++i){ 8 f[i]=i; v[i]=0; 9 } 10 } 11 int fin(int x){ 12 if(x!=f[x])f[x]=fin(f[x]); 13 return f[x]; 14 } 15 void uni(int x,int y){ 16 if((x=fin(x))==(y=fin(y))) t=1; 17 else f[x]=y; 18 } 19 int main(){ 20 int i,a,b,cnt; 21 while(scanf("%d%d",&a,&b)==2){ 22 if(a==-1&&b==-1)break; 23 init(); 24 t=0; 25 cnt=0;//树的棵数,大于1则为森林 26 if(a==0&&b==0){//空树(无结点) 27 printf("Yes\n");continue; 28 } 29 while(a){ 30 if(t==0) {uni(a,b);v[a]=v[b]=1;} 31 scanf("%d%d",&a,&b); 32 } 33 for(i=1;i<N;++i) 34 if(v[i]&&fin(i)==i) cnt++; 35 if(cnt==1&&t==0)printf("Yes\n"); 36 else printf("No\n"); 37 } 38 }
hdu1325 Is It A Tree?:判断是否为一棵树。与上题相比只需再判断除了根节点,是否每个结点的入度为1,再修改输出格式即可。
1 #include<cstdio> 2 const int N=100001; 3 int f[N]; 4 int v[N];//标记结点是否在图中 5 int in[N];//入度 6 int t; 7 void init(){ 8 for(int i=1;i<N;++i){ 9 f[i]=i; v[i]=0; in[i]=0; 10 } 11 } 12 int fin(int x){ 13 if(x!=f[x])f[x]=fin(f[x]); 14 return f[x]; 15 } 16 void uni(int x,int y){ 17 if((x=fin(x))==(y=fin(y))) t=1; 18 else f[x]=y; 19 } 20 int main(){ 21 int i,a,b,cnt,k=1; 22 while(scanf("%d%d",&a,&b)==2){ 23 if(a<0&&b<0)break; 24 init(); 25 t=0; 26 cnt=0;//树的棵数,大于1则为森林 27 if(a==0&&b==0){//空树(无结点) 28 printf("Case %d is a tree.\n",k++);continue; 29 } 30 while(a){ 31 if(t==0) {uni(a,b);v[a]=v[b]=1;in[b]++;} 32 if(in[b]>1)t=1; 33 scanf("%d%d",&a,&b); 34 } 35 for(i=1;i<N;++i) 36 if(v[i]&&fin(i)==i) cnt++; 37 if(cnt==1&&t==0)printf("Case %d is a tree.\n",k++); 38 else printf("Case %d is not a tree.\n",k++); 39 } 40 }
hdu1856 More is better:求最大集合中元素个数。注意朋友对为0时答案为1.
1 #include<cstdio> 2 const int N=1e7+1; 3 int f[N]; 4 int ma; 5 void init(){ 6 for(int i=1;i<N;++i) 7 f[i]=-1; 8 } 9 int fin(int x){ 10 if(f[x]<0) return x; 11 f[x]=fin(f[x]); 12 return f[x]; 13 } 14 void uni(int x,int y){ 15 if((x=fin(x))==(y=fin(y))) return; 16 else{ 17 f[x]+=f[y]; 18 f[y]=x; 19 if(-f[x]>ma) ma=-f[x]; 20 } 21 } 22 int main(){ 23 int n,a,b; 24 while(scanf("%d",&n)==1){ 25 ma=1; 26 init(); 27 while(n--){ 28 scanf("%d%d",&a,&b); 29 uni(a,b); 30 } 31 printf("%d\n",ma); 32 } 33 }
有点难度:
hdu1116 Play on Words(欧拉回路,并查集判连通)
题意:判断是否可以经过重组使得每个单词的第一个字母与前一个单词最后一个字母相同来打开门。
题解:每个单词首尾两个字母是关键,看成顶点,每个单词看成连接首尾两个字母的一条有向边。判断有向图基图是否连通(使用并查集判断),再判断是否存在有向欧拉通路/回路。
1 #include<cstdio> 2 #include<cstring> 3 using namespace std; 4 const int N=26; 5 int f[N],id[N],od[N],v[N]; 6 void init(){ 7 for(int i=0;i<N;++i){ 8 f[i]=i; 9 id[i]=od[i]=v[i]=0; 10 } 11 } 12 int fin(int x){ 13 if(x!=f[x])f[x]=fin(f[x]); 14 return f[x]; 15 } 16 void uni(int x,int y){ 17 if((x=fin(x))==(y=fin(y)))return; 18 else f[x]=y; 19 } 20 int main(){ 21 int t,i,a,b,n,cnt,q[N],c; 22 char s[1001]; 23 scanf("%d",&t); 24 while(t--){ 25 init(); 26 scanf("%d",&n); 27 while(n--){ 28 scanf("%s",s); 29 a=s[0]-‘a‘; 30 b=s[strlen(s)-1]-‘a‘; 31 od[a]++; id[b]++; 32 uni(a,b); 33 v[a]=v[b]=1; 34 } 35 for(cnt=i=0;i<N;++i) 36 if(v[i]&&fin(i)==i) 37 cnt++; 38 if(cnt>1){puts("The door cannot be opened.");continue;} 39 for(c=i=0;i<N;++i) 40 if(v[i]&&od[i]!=id[i]) 41 q[c++]=i; 42 if(c==0) puts("Ordering is possible."); 43 else if(c==2&&(od[q[0]]-id[q[0]]==1&&id[q[1]]-od[q[1]]==1||od[q[1]]-id[q[1]]==1&&id[q[0]]-od[q[0]]==1)) 44 puts("Ordering is possible."); 45 else puts("The door cannot be opened."); 46 } 47 return 0; 48 }
hdu1198 Farm Irrigation:求连通区域个数。
1 #include<cstdio> 2 #include<cstring> 3 using namespace std; 4 const int N=51; 5 int f[N*N]; 6 char g[N][N]; 7 //上右下左,有出口为1 8 int pipe[11][4]={{1,0,0,1},{1,1,0,0},{0,0,1,1},{0,1,1,0},{1,0,1,0},{0,1,0,1},{1,1,0,1},{1,0,1,1},{0,1,1,1},{1,1,1,0},{1,1,1,1}}; 9 int n,m; 10 void init(){ 11 for(int i=0;i<n*m;++i) 12 f[i]=i; 13 } 14 int fin(int x){ 15 if(x!=f[x])f[x]=fin(f[x]); 16 return f[x]; 17 } 18 void uni(int x,int y){ 19 if((x=fin(x))==(y=fin(y)))return; 20 else f[x]=y; 21 } 22 int main(){ 23 int i,j,cnt; 24 while(scanf("%d%d",&m,&n)==2){ 25 if(m<0||n<0)break; 26 init(); 27 for(i=0;i<m;++i) scanf("%s",g[i]); 28 for(i=0;i<m;++i){ 29 for(j=0;j<n;++j){ 30 if(i>0&&pipe[g[i][j]-‘A‘][0]==1&&pipe[g[i-1][j]-‘A‘][2]==1) 31 uni(i*n+j,(i-1)*n+j); 32 if(j>0&&pipe[g[i][j]-‘A‘][3]==1&&pipe[g[i][j-1]-‘A‘][1]==1) 33 uni(i*n+j,i*n+j-1); 34 } 35 } 36 for(cnt=i=0;i<m*n;++i) 37 if(fin(i)==i)cnt++; 38 printf("%d\n",cnt); 39 } 40 return 0; 41 }
hdu3635 Dragon Balls:记录移动次数。
1 #include<cstdio> 2 #include<cstring> 3 using namespace std; 4 const int N=10001; 5 int f[N],num[N]; 6 int c[N];//移动次数 7 int n; 8 void init(){ 9 for(int i=1;i<=n;++i){ 10 f[i]=i; c[i]=0; num[i]=1; 11 } 12 } 13 int fin(int x){ 14 if(x==f[x])return x; 15 int t=f[x]; 16 f[x]=fin(f[x]); 17 c[x]+=c[t];//本身加上父节点的移动次数 18 return f[x]; 19 } 20 void uni(int x,int y){ 21 if((x=fin(x))==(y=fin(y)))return; 22 else{ 23 f[x]=y; 24 num[y]+=num[x]; 25 c[x]=1;//根节点移动一次 26 } 27 } 28 int main(){ 29 int t,q,a,b,cnt,k=1; 30 char s[3]; 31 scanf("%d",&t); 32 while(t--){ 33 scanf("%d%d",&n,&q); 34 init(); 35 printf("Case %d:\n",k++); 36 while(q--){ 37 scanf("%s",s); 38 if(s[0]==‘T‘){ 39 scanf("%d%d",&a,&b); 40 uni(a,b); 41 } 42 else{ 43 scanf("%d",&a); 44 int x=fin(a); 45 printf("%d %d %d\n",x,num[x],c[a]); 46 } 47 } 48 } 49 return 0; 50 }
hdu2473 Junk-Mail Filter:并查集删点,对每个结点建立虚根。
1 #include<cstdio> 2 #include<cstring> 3 using namespace std; 4 const int N=1200001; 5 int f[N],v[N]; 6 int n,nn,m; 7 void init(){ 8 for(int i=0;i<n;++i) f[i]=i+n; 9 for(int i=n;i<nn+m;++i) f[i]=i; 10 } 11 int fin(int x){ 12 if(x!=f[x])f[x]=fin(f[x]); 13 return f[x]; 14 } 15 void uni(int x,int y){ 16 if((x=fin(x))==(y=fin(y)))return; 17 else f[x]=y; 18 } 19 int main(){ 20 int t,i,a,b,cnt,k=1; 21 char s[3]; 22 while(scanf("%d%d",&n,&m),n||m){ 23 nn=2*n; 24 memset(v,0,sizeof(v)); 25 init(); 26 while(m--){ 27 scanf("%s",s); 28 if(s[0]==‘M‘){ 29 scanf("%d%d",&a,&b); 30 uni(a,b); 31 } 32 else{ 33 scanf("%d",&a); 34 f[a]=nn++; 35 } 36 } 37 for(cnt=i=0;i<n;++i) 38 if(v[fin(i)]==0) 39 {v[fin(i)]=1;cnt++;} 40 printf("Case #%d: %d\n",k++,cnt); 41 } 42 return 0; 43 }
hdu3172 Virtual Friends:映射。(吐槽:输入坑爹- -+)
1 #include<cstdio> 2 #include<map> 3 #include<iostream> 4 using namespace std; 5 const int N=100001; 6 int f[N],num[N]; 7 int n; 8 void init(){ 9 for(int i=1;i<N;++i){ 10 f[i]=i; num[i]=1; 11 } 12 } 13 int fin(int x){ 14 if(x!=f[x])f[x]=fin(f[x]); 15 return f[x]; 16 } 17 void uni(int x,int y){ 18 if((x=fin(x))==(y=fin(y))) 19 printf("%d\n",num[x]); 20 else{ 21 f[x]=y; 22 num[y]+=num[x]; 23 printf("%d\n",num[y]); 24 } 25 } 26 map<string,int>p; 27 int main(){ 28 int t,cnt; 29 char a[21],b[21]; 30 while(scanf("%d",&t)==1){ 31 while(t--){ 32 cnt=1; 33 scanf("%d",&n); 34 init(); 35 p.clear(); 36 while(n--){ 37 scanf("%s %s",a,b); 38 if(!p[a])p[a]=cnt++; 39 if(!p[b])p[b]=cnt++; 40 uni(p[a],p[b]); 41 } 42 } 43 } 44 return 0; 45 }
hdu1558 Segment set:并查集,线段相交(快速跨立排斥试验看不懂,留着等以后我开窍了再学。。。)
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 const int N=1001; 5 int f[N],num[N]; 6 int n; 7 struct Point{ 8 double x,y; 9 }s[N],e[N]; 10 double mul(Point a,Point c,Point b){ 11 return (c.x-a.x)*(b.y-a.y)-(b.x-a.x)*(c.y-a.y); 12 } 13 bool LineSegmentIntersect(Point a,Point b,Point c,Point d){ 14 if(min(a.x,b.x)>max(c.x,d.x)) return 0; 15 if(min(a.y,b.y)>max(c.y,d.y)) return 0; 16 if(max(a.x,b.x)<min(c.x,d.x)) return 0; 17 if(max(a.y,b.y)<min(c.y,d.y)) return 0; 18 if(mul(a,c,b)*mul(a,b,d)<0) return 0; 19 if(mul(c,a,d)*mul(c,d,b)<0) return 0; 20 return 1; 21 } 22 void init(){ 23 for(int i=1;i<=n;++i){ 24 f[i]=i; num[i]=1; 25 } 26 } 27 int fin(int x){ 28 if(x!=f[x])f[x]=fin(f[x]); 29 return f[x]; 30 } 31 void uni(int x,int y){ 32 if((x=fin(x))==(y=fin(y)))return; 33 else{ 34 f[x]=y; 35 num[y]+=num[x]; 36 } 37 } 38 int main(){ 39 int t,cnt,i,j,k; 40 char a[3]; 41 scanf("%d",&t); 42 while(t--){ 43 scanf("%d",&n); 44 init(); 45 i=0; 46 while(n--){ 47 scanf("%s",a); 48 if(a[0]==‘P‘){ 49 i++; 50 scanf("%lf%lf%lf%lf",&s[i].x,&s[i].y,&e[i].x,&e[i].y); 51 for(j=1;j<i;++j){ 52 if(LineSegmentIntersect(s[i],e[i],s[j],e[j])) 53 uni(i,j); 54 } 55 } 56 else{ 57 scanf("%d",&k); 58 printf("%d\n",num[fin(k)]); 59 } 60 } 61 if(t)printf("\n"); 62 } 63 return 0; 64 }
hdu3461 Code Lock(并查集,二分求幂)英语渣表示第一遍看完题目一脸懵逼,然后直接百度题意orz
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 const int N=1e7+5; 5 const int mod=1e9+7; 6 typedef long long ll; 7 int f[N]; 8 int n; 9 int pow(int n){ 10 ll a=26; 11 ll r=1; 12 while(n){ 13 if(n&1) r=(r*a)%mod; 14 a=(a*a)%mod; 15 n>>=1; 16 } 17 return int(r); 18 } 19 void init(){ 20 for(int i=1;i<=n+1;++i){ 21 f[i]=i; 22 } 23 } 24 int fin(int x){ 25 if(x!=f[x])f[x]=fin(f[x]); 26 return f[x]; 27 } 28 int uni(int x,int y){ 29 if((x=fin(x))==(y=fin(y)))return 0; 30 else{ 31 f[x]=y; 32 return 1; 33 } 34 } 35 int main(){ 36 int m,cnt,a,b; 37 while(scanf("%d%d",&n,&m)==2){ 38 init(); 39 cnt=0;//"不同"的区间数 40 while(m--){ 41 scanf("%d%d",&a,&b); 42 cnt+=uni(a,b+1);//[1,3]、[4,5]和[1,5]“相同”,uni(l,r+1)即可判断 43 } 44 printf("%d\n",pow(n-cnt)); 45 } 46 return 0; 47 }
标签:
原文地址:http://www.cnblogs.com/GraceSkyer/p/5766520.html