zoukankan      html  css  js  c++  java
  • 并查集练习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
    ",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
    ",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
    ");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
    ");
    36         else printf("No
    ");
    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.
    ",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.
    ",k++);
    38         else printf("Case %d is not a tree.
    ",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
    ",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
    ",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:
    ",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
    ",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
    ",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
    ",num[x]);
    20     else{
    21         f[x]=y;
    22         num[y]+=num[x];
    23         printf("%d
    ",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
    ",num[fin(k)]);
    59             }
    60         }
    61         if(t)printf("
    ");
    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
    ",pow(n-cnt));
    45     }
    46     return 0;
    47 }
    View Code
  • 相关阅读:
    RMAN 增量备份 的 对象测试
    小论工具类App的盈利之道
    linux下二进制文件比较程序
    [置顶] 对iOS开发有用的一些自动化处理脚本
    [Win8]Windows8开发笔记(八):数据绑定的基础
    NetBeans 时事通讯(刊号 # 116 Sep 11, 2010)
    域名信息证实 JavaEye 已被 CSDN 收购
    插件架构简介
    GAE for Java exception: no matching index found.
    Java 7 最快要到 2012 年中发布
  • 原文地址:https://www.cnblogs.com/GraceSkyer/p/5766520.html
Copyright © 2011-2022 走看看