Algorithm --> 并查集

并查集

主要解决图的连通性问题,比如:

  1、随意给你两个点,让你判断它们是否连通;

  2、问你整幅图一共有几个连通分支;

初始化:

void init(int size) 
{
    for(int i = 0; i < size; i++) pre[i] = i;
}

代码(非递归):

int find(int x)           //查找根节点
{ 
    int r = x;
    while(pre[r] != r) r =  pre[r];    //返回根节点 r
          
    int i = x , j ;
    while(i != r)     //路径压缩
    {
         j = pre[i];   // 在改变上级之前用临时变量  j 记录下他的值 
         pre[i] = r ;  //把上级改为根节点
         i = j;
    }
    return r ;
}

void join(int x,int y)     //判断x y是否连通     
{
    int fx = find(x);
    int fy = find(y);

    if(fx != fy)    //如果已经连通,就不用管了; 如果不连通,就把它们所在的连通分支合并起
        pre[fx]=fy;
}

递归法:

int find(int x)
{
    if (x != pre[x]) 
        pre[x] = find(pre[x]); 

    return pre[x];
}     

求连接非连通图,需要几条边:

#include <iostream>
using namespace std;

int N, E, Answer;
int pre[1000];

int find(int x)
{
    int r = x;

    while(pre[r] != r)   //找父亲 
        r = pre[r];

    int i = x, j;
    while(i != r)   //路径压缩 
    {
       j = pre[i];
       pre[i] = r;
       i = j;
    }

   return r;
}

int find2(int x)   //递归
{   
    if (x != pre[x])      
      pre[x] = find(pre[x]);
return pre[x]; } int main() { int x, y, p1, p2; while(cin >> N, N) //顶点数 { Answer = N-1; //N个顶点需要N-1条边 for(int i = 1; i <= N; i++)         pre[i] = i; //每个顶点的父亲都是自己 cin >> E; //边数 while(E--) { cin >> p1 >> p2; x = find(p1); y = find(p2); if(x != y) //如果是不连通的,把这两个分支连起来, 分支的总数就减少了1,还需建的路也就减了1 { pre[y]=x; Answer--; } //如果两点已经连通了,那么这条路只是在图上增加了一个环 //对连通性没有任何影响,无视掉 } cout << Answer << endl; //最后输出还要修的路条数 }
}

输入:

4 2
1 2
3 4

7 5
1 2
2 3
3 4
1 5
6 7
原文地址:https://www.cnblogs.com/jeakeven/p/4696815.html