• 并查集及其应用


    并查集初步

    PS:今天入手了一台1993年产的IBM Model M弹簧轴机械键盘,真好用呀真好用~  ^_^

    并查集经常借助树形数据结构来实现。

    设Father[i]表示元素i所属于的集合编号。初始化Father[x]=x;即每个节点都是单独的一棵树

    并查集具有两项基本操作:

    1. Find(i) :返回元素i所属于的集合的编号

    Int Find(int x)

    {

             If (x!=Father[x])

                   Father[x]=Find(Father[x])     //此处用到了路径压缩优化

                Return Father[x];

          }

    1. Union(x,y):合并元素x和元素y所在的集合

    Void Union(int x,int y)

    {

             Int fx=Find(x);

             Int fy=Find(y);

             If (fx!=fy)

                   Father[fy]=fx;

          }

     

    来看一个简单的例题:

    Eg1:亲戚(原题网上一抓一大把T^T)

    赤裸裸的并查集,不再解释了~

     1 #include <iostream>
     2 #include <cstring>
     3 using namespace std;
     4 int n,m,p,tx,ty,i,x,y,j;
     5 int f[10000];
     6 
     7 int find(int x)
     8 {
     9     if (f[x]!=x)
    10         f[x]=find(f[x]);
    11     return f[x];
    12 }
    13 
    14 void iunion(int x,int y)
    15 {
    16     int fx,fy;
    17     fx=find(x);
    18     fy=find(y);
    19     if (fx!=fy) 
    20         f[fx]=fy;
    21 }
    22 
    23 int main()
    24 {
    25     cin>>n>>m>>p;
    26     memset(f,0,sizeof(f));
    27     for (i=1;i<=n;i++)
    28         f[i]=i;
    29         
    30     for (i=1;i<=m;i++)
    31     {
    32         cin>>x>>y;
    33         iunion(x,y);
    34             for (j=1;j<=n;j++)  cout<<f[j]<<"  ";
    35             cout<<endl;
    36     }
    37         
    38     for (i=1;i<=p;i++)
    39     {
    40         cin>>x>>y;
    41         tx=find(x);
    42         ty=find(y);
    43         if (tx==ty) cout<<"yes"<<endl;
    44             else cout<<"no"<<endl;
    45     }
    46 }
    View Code

    Eg2:代码等式(原题见《算法艺术与信息学竞赛》P80 例题1)

    Solution:先将表达式中的字母按照a1、a2、a3、b1、b2……这样的形式展开,然后一一对应匹配即可。

    注意几个问题:

    1. C语言中的数组下标不能为负值,只能从0开始  T^T
    2. 求字符的ASCII:用强制类型转换:

          Char c=’a’

          Int i=c;           //那么i的值即’a’的ASCII码97

      1 #include <iostream>
      2 #include <cstring>
      3 #include <cstdio>
      4 using namespace std;
      5 
      6 int visited[1000];
      7 int lth[1000];
      8 int father[1000];
      9 int ch[2][1000];
     10 char s1[1000],s2[1000];
     11 int i,j,k,l1,l2,t1,t2,tmp,sum;
     12 
     13 int find(int x)
     14 {
     15     if (x!=father[x])
     16         father[x]=find(father[x]);
     17     return father[x];
     18 }
     19 
     20 void iunion(int x,int y)
     21 {
     22     int fx=find(x);
     23     int fy=find(y);
     24     if (fx!=fy)
     25         father[fy]=fx;
     26 }
     27 
     28 int main()
     29 {
     30     cin>>k;
     31     sum=0;
     32     for (i=1;i<=k;i++) 
     33     {
     34         cin>>lth[i];
     35         sum=sum+lth[i];    
     36     }
     37     cin>>s1;    cin>>s2;
     38     l1=strlen(s1);
     39     l2=strlen(s2);
     40     
     41     t1=1;
     42     for (i=0;i<l1;i++)
     43     {
     44         char tch=s1[i];
     45         switch (tch)
     46         {
     47         case '0':
     48             ch[1][t1]=0;
     49             t1++;
     50         case '1':
     51             ch[1][t1]=sum+1;
     52             t1++;
     53         default:
     54             int ci=tch;
     55              ci=ci-97+1;
     56              tmp=0;
     57              for (j=1;j<=ci-1;j++)
     58                  tmp=tmp+lth[j];
     59              tmp++;
     60              for (j=1;j<=lth[ci];j++)
     61              {
     62                  ch[1][t1]=tmp;
     63                  tmp++;
     64                  t1++;
     65              }
     66         }
     67     }
     68     
     69     t2=1;
     70     for (i=0;i<l2;i++)
     71     {
     72         char tch=s2[i];
     73         switch (tch)
     74         {
     75         case '0':
     76             ch[2][t2]=0;
     77             t2++;
     78         case '1':
     79             ch[2][t2]=sum+1;
     80             t2++;
     81         default:
     82             int ci=tch;
     83              ci=ci-97+1;
     84              tmp=0;
     85              for (j=1;j<=ci-1;j++)
     86                  tmp=tmp+lth[j];
     87              tmp++;
     88              for (j=1;j<=lth[ci];j++)
     89              {
     90                  ch[2][t2]=tmp;
     91                  tmp++;
     92                  t2++;
     93              }
     94         }
     95     }
     96     t1--;    t2--;
     97     
     98     //FOR DEBUG ONLY  >:>
     99     cout<<t1<<endl;
    100     for (i=1;i<=t1;i++)        cout<<ch[1][i]<<" ";
    101     cout<<endl;
    102     cout<<t2<<endl;
    103     for (i=1;i<=t2;i++)     cout<<ch[2][i]<<" ";
    104     cout<<endl;
    105     cout<<sum<<endl;
    106     cout<<"****************************************************"<<endl;
    107     
    108     memset(father,0,sizeof(father));
    109     for (i=1;i<=sum+1;i++)
    110         father[i]=i;
    111         
    112     for (i=1;i<=t1;i++)
    113         iunion(ch[1][i],ch[2][i]);
    114     int ans=1;        
    115     t1=find(0);    t2=find(sum+1);
    116     ////cout<<t1<<"   "<<t2<<endl;
    117     memset(visited,0,sizeof(visited));
    118     visited[t1]=1;    visited[t2]=1;
    119     for (i=1;i<=sum;i++)
    120     {
    121         tmp=find(i);
    122         if (!visited[tmp])
    123         {
    124             visited[tmp]=1;
    125             ans=ans*2;
    126         }
    127     }
    128     cout<<ans<<endl;
    129 }
    View Code

    Eg3:用并查集实现kruskal算法

     1 #include <iostream>
     2 using namespace std;
     3 
     4 struct abc
     5 {
     6     int x,y,dat;
     7 };
     8 
     9 struct abc e[1000];
    10 int f[1000];
    11 int i,j,k,ans,n,m,tx,ty,tmp;
    12 
    13 int find(int x)
    14 {
    15     if (x!=f[x])
    16         f[x]=find(f[x]);
    17     return f[x];
    18 }
    19 
    20 void iunion(int x,int y)
    21 {
    22     int fx=find(x);
    23     int fy=find(y);
    24     if (fx!=fy)
    25         f[fy]=fx;
    26 }
    27 
    28 void qsort(int l,int r)
    29 {
    30    int i,j,mid;
    31    struct abc t; 
    32    i=l;
    33    j=r;
    34    mid=e[(l+r)/2].dat;
    35    do{
    36        while (e[i].dat<mid) i++;
    37        while (e[j].dat>mid) j--;
    38        if (!(i>j))
    39        {
    40            t=e[i];
    41            e[i]=e[j];
    42            e[j]=t;
    43            i++;
    44            j--;
    45        }
    46    }while (i<=j);
    47    if (l<j) qsort(l,j);
    48    if (i<r) qsort(i,r);
    49 }
    50 
    51 int main()
    52 {
    53     
    54     cin>>n>>m;
    55     for (i=1;i<=m;i++)
    56     {
    57         cin>>tx>>ty>>tmp;
    58         e[i].x=tx;
    59         e[i].y=ty;
    60         e[i].dat=tmp;
    61     }
    62 
    63     for (i=1;i<=n;i++)
    64         f[i]=i;
    65     qsort(1,m);
    66     
    67     k=1;
    68     ans=0;
    69     for (i=1;i<=n-1;i++)
    70     {
    71         while (find(e[k].x)==find(e[k].y)) k++;
    72         iunion(e[k].x,e[k].y);
    73         ans=ans+e[k].dat;
    74         cout<<e[k].x<<" "<<e[k].y<<" "<<e[k].dat<<endl;
    75     }
    76     
    77     cout<<ans<<endl;
    78 }
    View Code

     

  • 相关阅读:
    flink 使用processFunction函数的sideOutPut实现filter操作(java版)
    flink 状态编程之RichFlatMapFunction用法-java
    java flink之eventTime和window
    java spark sql 计算各个省份广告点击数的top3
    java spark 计算各个省份广告点击数的top3
    java streaming转换算子window,countByWindow
    java spark转换算子sortByKey
    java spark转换算子join、leftOuterJoin、rightOuterJoin、fullOuterjoin
    java spark转换算子groupByKey、reduceByKey、aggregateByKey
    java spark转换算子union、intersection、subtract
  • 原文地址:https://www.cnblogs.com/pdev/p/3955388.html
Copyright © 2020-2023  润新知