Kruscal algorithm of minimum spanning tree, union check set and ring removal (detailed illustration, C++)

"Minimum Spanning Tree Kruscal Algorithm, Union Check Code"

Foreword: This is the first time to write an algorithm blog hhh without the sample questions. After reading a lot of information on the Internet, I summarized it in the blog.

1. The idea of ​​Kruscal algorithm:
① When we do the minimum spanning tree problem, we need to use an edge structure array:

typedef struct stu              ///边结构体
{
    
    
    int u;			//边起始节点
    int v;			//边结尾节点
    int len;		//边权值
}edge;
edge a[10005];		//边的结构体数组

②Kruskal's algorithm selects the edges with the smallest weight from all the edges in turn and adds them until the added edge is equal to the number of nodes -1 (of course, if the newly added edge forms a ring, it is discarded)
③ So we need to sort the array from small to large first. There may be a small problem at this time. How to sort the structure, then we need to use C++ sort and pseudo-functions to achieve it. First, we need to define a pseudo-function compareEdge :

bool compareEdge(edge a1,edge a2)       ///伪函数
{
    
    
    return a1.len < a2.len;
}

Then use sort():

sort(&a[1],&a[n+1],compareEdge);          ///排序边权

(If you are not familiar with STL and pseudo-functions, go to make up the lesson yourself)
④Now we start traversing the array from a[1], we have to consider whether it will form a ring every time we select an edge, usually we need to use the combined search to judge , Let’s explain the idea of ​​combining and checking:

※Here is an analogy : now there are 3 people, 2 is 1 colleague, and 3 is 1 colleague.
So how do we judge whether these three people are in a colleague relationship? We use an array person[i] to indicate who is the highest-level boss of the i-th person. At the beginning, everyone’s boss is its own person. [i] = i , for example, 2 is a colleague of 1, then person[1] = 2, which is equivalent to 2 is now the boss of 1. 3 is a colleague of 1, then person[1] should be equal to 3 again. To avoid this phenomenon, you must find the boss of 1 first, and then **update the "boss"** of the boss of 1 to realize the link of the relationship (I It feels like the idea of ​​a linked list), the current boss of 1 is 2, then find person[2], the original person[2] is itself, now we need to update it to 3, then the structure we imagined is like this: the
Insert picture description here
person array should It's like this:
Insert picture description here

How do we find someone’s boss?

int findHead(int x)
{
    
    
    while(person[x] != x)		//只要他的boss不是他自己
        x = person[x];			//x等于他的下一级
    return x;					//最后return -> boss的值
}	

When we learn to think, we will find that 1 and 2 are colleagues, and 1 and 3 are colleagues. Then 2 and 3 must be colleagues. The values ​​of person[2] and person[3] are the same. If you add A 2 and 3 are colleagues (edges), then a ring is formed, so when the boss of au is equal to the boss of av, a ring will appear:

int judge(int x)			//判断每次遍历的最小边
{
    
    
    int father;
    int father1 = findHead(a[x].u);		//找Boss1
    int father2 = findHead(a[x].v);		//找Boss2
    if(father1 == father2){
    
    				//相等
        cout << "第"<<x<<"次有环"<<endl;			//有环
        return 0;
    }
    else
    {
    
    
         father = findHead(a[x].u);
         person[father] = a[x].v;		//没有环就更新当前点的boss
         ans += a[x].len;				//最小生成树+=len
        cout << "第"<<x<<"次无环"<<endl;
         return 1;
    }
}

Finally, it is judged that the number of edges that have been added is equal to the number of nodes-1 , and the minimum spanning tree is completed:

 for(int i = 1;i<=n;i++)
    {
    
    
        if(judge(i)) num++;			//如果判断没有环,边数++
        if(num == n - 1) break;	
    }

Finally, the complete code:

#include<bits/stdc++.h>
using namespace std;

typedef struct stu              ///边结构体
{
    
    
    int u;
    int v;
    int len;
}edge;

bool compareEdge(edge a1,edge a2)       ///伪函数
{
    
    
    return a1.len < a2.len;
}

int person[10005];
edge a[10005];
int ans = 0;

int findHead(int x)
{
    
    
    while(person[x] != x)
        x = person[x];
    return x;
}

int judge(int x)
{
    
    
    int father;
    int father1 = findHead(a[x].u);
    int father2 = findHead(a[x].v);
    if(father1 == father2){
    
    
        cout << "第"<<x<<"次有环"<<endl;
        return 0;
    }
    else
    {
    
    
         father = findHead(a[x].u);
         person[father] = a[x].v;
         ans += a[x].len;
        cout << "第"<<x<<"次无环"<<endl;
         return 1;
    }
}

int main(){
    
    

    int n,m;
    int num = 0;
    cin >> n >> m;
    for(int i=1;i<=10005;i++)
    {
    
    
        person[i] = i;         ///初始化person数组
    }
    for(int i=1;i<=n;i++)
    {
    
    
        cin >>a[i].u >>a[i].v>>a[i].len;        ///输入边数据
    }
    sort(&a[1],&a[n+1],compareEdge);          ///排序边权数组
    for(int i = 1;i<=m;i++)
    {
    
    
        if(judge(i)) num++;
        if(num == n - 1) break;
    }
    cout << "最小生成树权重为:"<<ans;
    return 0;
}

Test a use case:
Please add picture description

Please add picture description

Afterword: This article is really hard and rewarding. I hope it can help students who have just learned the minimum spanning tree!

Guess you like

Origin blog.csdn.net/Kyrie_irving_kun/article/details/113820315