Algorithme Kruscal d'arbre couvrant minimum, jeu de contrôle d'union et suppression de l'anneau (illustration détaillée, C ++)

"Algorithme Kruscal Spanning Tree minimum, code de contrôle de l'Union"

Avant-propos: C'est la première fois que vous rédigez un blog d'algorithmes sans les exemples de questions. Après avoir lu beaucoup d'informations sur Internet, je les ai résumées dans le blog.

1. L'idée de l'algorithme de Kruscal:
① Lorsque nous faisons le problème d'arbre couvrant minimum, nous devons utiliser un tableau de structure d'arête:

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

L'algorithme de Kruskal sélectionne tour à tour les arêtes avec le poids le plus petit de toutes les arêtes et les ajoute jusqu'à ce que l'arête ajoutée soit égale au nombre de nœuds -1 (bien sûr, si l'arête nouvellement ajoutée forme un anneau, elle est rejetée)
Donc nous devons trier le tableau du plus petit au plus grand en poids. Il peut y avoir un petit problème pour le moment. Comment trier la structure, alors nous devons utiliser le tri C ++ et des pseudo-fonctions pour y parvenir. Premièrement, nous devons définir une pseudo-fonction compareEdge :

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

Ensuite, utilisez sort ():

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

(Si vous n'êtes pas familier avec STL et les pseudo-fonctions, allez faire la leçon vous-même)
④Maintenant, nous commençons à parcourir le tableau à partir d'un [1], nous devons nous demander s'il formera un anneau à chaque fois que nous sélectionnons une arête, généralement nous devons utiliser une recherche d'union pour déterminer, Expliquons l'idée de combiner et de vérifier:

※ Voici une analogie : maintenant il y a 3 personnes, 2 est 1 collègue et 3 est 1 collègue.
Alors, comment pouvons-nous juger si ces trois personnes sont dans une relation de collègue? Nous utilisons une personne du tableau [i] pour indiquer qui est le chef de plus haut niveau de la i-ième personne. Au début, le patron de chacun est sa propre personne. [i] = i , par exemple, 2 est un collègue de 1, alors la personne [1] = 2, ce qui équivaut à 2 est maintenant le patron de 1. 3 est un collègue de 1, alors personne [1] doit être à nouveau égal à 3. Pour éviter ce phénomène, vous devez d'abord trouver le boss de 1, puis ** mettre à jour le "boss" ** du boss de 1 à réaliser le lien de la relation (I Cela ressemble à l'idée d'une liste chaînée), le patron actuel de 1 est 2, puis trouver la personne [2], la personne d'origine [2] est elle-même, et maintenant elle doit être mis à jour à 3, alors la structure que nous avons imaginée est comme ceci: le
Insérez la description de l'image ici
tableau de personnes devrait C'est comme ceci:
Insérez la description de l'image ici

Comment trouver le patron de quelqu'un?

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

Lorsque nous apprenons à penser, nous constaterons que 1 et 2 sont des collègues et 1 et 3 sont des collègues. Alors 2 et 3 doivent être des collègues. Les valeurs de personne [2] et de personne [3] sont les mêmes. Si vous ajoutez A 2 et 3 sont des collègues (arêtes), puis un anneau se forme, donc quand le boss de au est égal au boss de av, un anneau apparaîtra:

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;
    }
}

Enfin, il est jugé que le nombre d'arêtes qui ont été ajoutées est égal au nombre de nœuds-1 , et l'arbre couvrant minimum est terminé:

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

Enfin, le code complet:

#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;
}

Testez un cas d'utilisation:
Veuillez ajouter une description de l'image

Veuillez ajouter une description de l'image

Postface: Cet article est vraiment difficile et enrichissant. J'espère qu'il pourra aider les étudiants qui viennent d'apprendre l'arborescence minimale!

Je suppose que tu aimes

Origine blog.csdn.net/Kyrie_irving_kun/article/details/113820315
conseillé
Classement