并查集练习1

举头望明月,低头敲代码。。。00F0A1AF

推荐学习地址:http://www.cnblogs.com/cyjb/p/UnionFindSets.html

简单:

hdu1213 How Many Tables:新手必秒

 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 }
View Code

 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 }
View Code

 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 }
View Code

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 }
View Code

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 }
View Code

有点难度:

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 }
View Code

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 }
View Code

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 }
View Code

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 }
View Code

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 }
View Code

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 }
View Code

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 }
View Code

 

posted @ 2016-08-12 21:00  GraceSkyer  阅读(567)  评论(0编辑  收藏  举报

~~~~~~ACM大牛语录,激励一下~~~~~~

为了世界的和平,为了女生的安全,我拼命做题,做题,做题!

用最短的时间,刷最多的题!

给我一滴泪,我就看到了你全部的海洋!

seize the hour, seize the day.

人生难免有无奈,幸福走远了,或是感叹幸福来迟了.其实我一直相信,无论手中的幸福是多么微不足道的感觉,我会把握住那每一分,每一秒,当幸福依旧像那百鸟般飞逝,终究无法掌握时,我会感谢它,曾经降临过!

A自己的题,让别人郁闷去吧

WA肠中过,AC心中留 TLE耳边过,AC特别牛

天然的悲苦和伤逝,过去有过,以后还会有

^*^一步一步往上爬^*^

AC就像练级,比赛就像PK. 练级不如PK好玩

其实,世上本没有ACM,AC的人多了,也便有了!

AC无止尽~ Seek you forever~

找呀找呀找水题,找到一个AC一个呀!

AC是检验程序的唯一标准。

真的猛士,敢于直面惨淡的人生,敢于正视淋漓的鲜血……