并查集

来源:互联网 发布:海尔32电视网络售价 编辑:程序博客网 时间:2024/05/19 23:04
算法需要以下几个子过程:
  (1) 开始时,为每个人建立一个集合SUB-Make-Set(x);
  (2) 得到一个关系后a,b,合并相应集合SUB-Union(a,b);

  (3) 此外我们还需要判断两个人是否在同一个集合中,这就涉及到如何标识集合的问题。我们可以在每个集合中选一个代表标识集合,因此我们需要一个子过程给出每个集合的代表元SUB-Find-Set(a)。于是判断两个人是否在同一个集合中,即两个人是否为亲戚,等价于判断SUB-Find-Set(a)=SUB-Find-Set(b)。

畅通工程 杭电1232

#include <iostream>
using std::cin;
using std::cout;
using std::endl;

const int max = 1000;
int father[max];
int count;//连通n个点需要n-1条边
////////////////////////
void make_set(int n)//初始化并查集 ,初始化集合数count
{
             int i;
             for( i = 0 ; i < n ; i++ )
             father[i] = i;
             count = n;
}
///////////////////////
int find_set(int n)//查找所属集合并压缩路径 
{
             if(n==father[n])
             return n;
             else father[n] = find_set(father[n]);
             return father[n]; 
}
///////////////////////
void Union(int a,int b)//合并 ,并依情况减少集合计数 count
{
     int set_a = find_set(a);
     int set_b = find_set(b);
     //找到头,对头处理(set_a,set_b是find_set的结果,所以它们各自代表了一个集合,即各是一个根)
     if( set_a == set_b )return;
     else
     {
         father[set_a] = father[set_b];
         count--;
     }
}

int main()
{
    int N,M,i,j,k;
    while(cin>>N)
    {
                 if(N==0)break;
                 
                 make_set(N);
                 
                 cin>>M;
                 for( i = 0 ; i < M ; i++ )
                 {
                      cin>>j>>k;
                      Union(j-1,k-1);
                 }
                 cout<<count-1<<endl;
    }
    system("pause");
    return 0;
}