[Teoría de grafos - Clase 8] Algoritmo de Kruskal para el problema del árbol de expansión mínimo

ฅ(๑˙o˙๑)ฅ Hola a todos, bienvenidos a mi blog: La serie de notas de aprendizaje para los algoritmos de aprendizaje de Ania se actualiza continuamente~

A



I. Introducción

Definición mínima del árbol de expansión:

Un árbol de expansión de un gráfico conectado con n nodos es un subgráfico conectado mínimo del gráfico original, contiene todos los n nodos del gráfico original y tiene la menor cantidad de aristas que mantienen el gráfico conectado. El árbol de expansión mínimo se puede calcular mediante el algoritmo kruskal o el algoritmo prim.

El árbol de expansión mínimo es en realidad 最小权重生成树la abreviatura de


Segundo, algoritmo de Kruskal para encontrar el árbol de expansión mínimo

Complejidad temporal O(mlogm) - m es el número de aristas, adecuado para encontrar el árbol de expansión mínimo de la red con aristas dispersas

El algoritmo de Kruskal se basa en la idea de codicioso.

Breve descripción del algoritmo de Kruskal

Primero, organizamos todos los bordes de menor a mayor según el peso, y luego seleccionamos cada borde en orden. Si los dos extremos de este borde no pertenecen al mismo conjunto, entonces únalos hasta que todos los puntos pertenezcan al mismo fijado hasta la recogida.

Pasos de implementación

  • Clasifique todos los bordes en orden ascendente de acuerdo con el tamaño de los pesos y luego júzguelos uno por uno de menor a mayor.

  • Si esta arista no forma un circuito con todas las aristas previamente seleccionadas, seleccione esta arista para dividir, de lo contrario, deséchela.

  • Hasta que una red conectada con n vértices filtra n-1 aristas.

  • Los bordes seleccionados y todos los vértices constituyen el árbol de expansión mínimo de esta red conectada.

El método para juzgar si habrá un bucle es: use union search .

A cada vértice se le asigna un conjunto diferente en el estado inicial.
Recorre cada borde del proceso para determinar si los dos vértices están en un conjunto.
Si los dos vértices en el borde están en un conjunto, significa que los dos vértices están conectados y este borde no es necesario. Si no está en un conjunto, se requiere este borde.

int Kruskal()
{
    
    
    int res=0,cnt=0;//res记录最小生成树的树边权重之和,cnt记录的是全部加入到树的集合中边的数量(可能有多个集合)
    for(int i=0;i<m;i++)
    {
    
    
        int a=edges[i].a,b=edges[i].b,w=edges[i].w;
        if(find(a)!=find(b))
        //如果 a b 不在一个集合中
        {
    
    
            p[find(a)]=p[find(b)];//将a,b所在的两个集合连接起来
            cnt++;//因为加入的是a-b的这一条边,将a,b所在的两个集合连接之后,全部集合中的边数加1
            res+=w;//加入到集合中的边的权重之和
        }
    }

    if(cnt==n-1) return res;//树中有n个节点便有n-1条边,可以生成最小生成树
    else return 0x3f3f3f3f;//如果cnt不等于n-1的话,说明无法生成有n个节点的树
}

ejemplo:

Dado un gráfico no dirigido con n puntos y m aristas, puede haber múltiples aristas y bucles automáticos en la gráfica, y los pesos de las aristas pueden ser negativos.
Encuentre la suma de los pesos de los bordes del árbol del árbol de expansión mínimo y la salida es imposible si el árbol de expansión mínimo no existe.

Muestras de entrada:
4 5
1 2 1
1 3 2
1 4 3
2 3 2
3 4 4
Muestras de salida:
6

#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;

const int N=200010,M=100010;         

int p[M];
int n,m;

struct Edge
{
    
    
    int a,b,w;
//重载小于号,因为在给边排序的时候是按照边的权重进行排序的,这样当两个边进行比较的时候就会使用它们的权重进行比较了
     bool operator< (const Edge &W)const
    {
    
    
        return w < W.w;
    }
}edges[N];

int find(int x)
{
    
    
    if(p[x]!=x) p[x]=find(p[x]);
    else return x;
} 

int Kruskal()
{
    
    
    int res=0,cnt=0;//res记录最小生成树的树边权重之和,cnt记录的是全部加入到树的集合中边的数量(可能有多个集合)
    for(int i=0;i<m;i++)
    {
    
    
        int a=edges[i].a,b=edges[i].b,w=edges[i].w;
        if(find(a)!=find(b))
        {
    
    
            p[find(a)]=p[find(b)];//将a,b所在的两个集合连接起来
            cnt++;//因为加入的是a-b的这一条边,将a,b所在的两个集合连接之后,全部集合中的边数加1
            res+=w;//加入到集合中的边的权重之和
        }
    }

    if(cnt==n-1) return res;//可以生成最小生成树
    else return 0x3f3f3f3f;//树中有n个节点便有n-1条边,如果cnt不等于n-1的话,说明无法生成有n个节点的树
}

int main()
{
    
    
    cin>>n>>m;

    for(int i=0;i<n;i++) p[i]=i;//初始化并查集

    for(int i=0;i<m;i++)//读入每条边
    {
    
    
        int a,b,w;
        cin>>a>>b>>w;
        edges[i]={
    
    a,b,w};
    }

    sort(edges,edges+m);//将边的权重按照大小一一排序

    int t=Kruskal();

    if(t==0x3f3f3f3f) puts("impossible\n");
    else cout<<t<<endl;

    return 0;
}

Al final

Mo Yan, la verdad es infinita, cada centímetro de progreso tiene su propio

inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/m0_63233163/article/details/125608760
Recomendado
Clasificación