克魯斯卡爾算法(Kruskal算法)(最小生成樹算法)-貪心


克魯斯卡爾算法:Kruskal算法是一種用來查找最小生成樹的算法,由Joseph Kruskal在1956年發表。用來解決同樣問題的還有Prim算法和Boruvka算法等。三種算法都是貪心算法的應用。和Boruvka算法不同的地方是,Kruskal算法在圖中存在相同權值的邊時也有效。

基本思想:先構造一個只含 n 個頂點、而邊集為空的子圖,把子圖中各個頂點看成各棵樹上的根結點,之后,從網的邊集 E 中選取一條權值最小的邊,若該條邊的兩個頂點分屬不同的樹,則將其加入子圖,即把兩棵樹合成一棵樹,反之,若該條邊的兩個頂點已落在同一棵樹上,則不可取,而應該取下一條權值最小的邊再試之。依次類推,直到森林中只有一棵樹,也即子圖中含有 n-1 條邊為止。

發現一個好的視頻:https://www.bilibili.com/video/BV1Eb41177d1

下圖為初始圖、只含有點的森林和點與點之間的聯系

循環找權值最小的邊

 

 依次向下循環...

  

輸入:

6 10
1 2 6
1 3 1
1 4 5
2 3 5
2 5 3
3 4 5
3 5 6
3 6 4
4 6 2
5 6 6

輸出:

V1-V3=1
V4-V6=2
V2-V5=3
V3-V6=4
V5-V6=5
15

代碼:

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

#define MAX 100

int Find(int parent[],int i)
{
    while(parent[i]>0)
    {
        i=parent[i];
    }
    return i;
}
void Kruskal(int u[],int v[],int w[],int n,int m)
{
    int parent[MAX];
    int sum=0;
    for(int i=1;i<=n;i++) //初始化
    {
        parent[i]=0;
    }
    int a,b;
    for(int i=1;i<=m;i++)
    {
        a=Find(parent,u[i]);
        b=Find(parent,v[i]);
        if(a!=b) //a==b說明成環
        {
            parent[a]=b;
            cout<<"V"<<a<<"-"<<"V"<<b<<"="<<w[i]<<endl;
            sum+=w[i];
        }
    }
    cout<<sum;
}
int main()
{
    int n,m;
    int u[MAX],v[MAX],w[MAX];
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        cin>>u[i]>>v[i]>>w[i];
    }
    for(int i=1;i<=m;i++)  //排序
    {
        int min=i;
        for(int j=i+1;j<=m;j++)
        {
            if(w[min]>w[j])
            {
                min=j;
            }
        }
        swap(u[i],u[min]);
        swap(v[i],v[min]);
        swap(w[i],w[min]);
    }
    Kruskal(u,v,w,n,m);
    return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM