1. 程式人生 > >最小生成樹——Kruscal(克魯斯卡爾算法)

最小生成樹——Kruscal(克魯斯卡爾算法)

else 一個 oot n) struct kruscal stream .html d+

一、核心思想

? 將輸入的數據由小到大進行排序,再使用並查集算法(傳送門)將每個點連接起來,同時求和。

? 個人認為這個算法比較偏向暴力,有些題可能會超時。

二、例題 洛谷—P3366

題目地址:https://www.luogu.org/problemnew/show/P3366

這是一道非常好的克魯斯卡爾算法的模板題。

題目描述

如題,給出一個無向圖,求出最小生成樹,如果該圖不連通,則輸出orz

輸入輸出格式

輸入格式:

第一行包含兩個整數N、M,表示該圖共有N個結點和M條無向邊。(N<=5000,M<=200000)

接下來M行每行包含三個整數Xi、Yi、Zi,表示有一條長度為Zi的無向邊連接結點Xi、Yi

輸出格式:

輸出包含一個數,即最小生成樹的各邊的長度之和;如果該圖不連通則輸出orz

輸入輸出樣例

輸入樣例:

    4 5
    1 2 2
    1 3 2
    1 4 3
    2 3 4
    3 4 3

輸出樣例:

    7

AC代碼:

這段是符合題意的改良代碼,一開始我提交的時候沒有做orz的輸出,由於題的數據問題導致沒有設計orz也過了??????。

#include<iostream>
#include<algorithm>
#include<cstdio>

using namespace std;
int root[500000];
int book[500000];
int n, m;
int ans;

struct node
{
    int be, en, dis;
}road[500000];

bool cmp( node a, node b)
{
    return a.dis < b.dis;
}

int findx( int a)
{

    if (a == root[a])
        return a;
    else
        return root[a] = findx(root[a]);
}

void mix( int a, int b)
{
    int fr = findx(a), lr = findx(b);
    if(fr != lr)
        root[b] = fr;
}

int kruscal()
{
    int sum = 0;
    int t1, t2;
    for( int i = 1; i <= m; i++)
    {
        t1 = findx(road[i].be);
        t2 = findx(road[i].en);
        if( t1 != t2)
        {
            sum += road[i].dis;
            ans++;
            mix(t1,t2);
        }
        if(ans == n-1)
            break;
    }
    return sum;
}

int main()
{
    int sum;
    
    cin >> n >> m;
    for( int i = 1; i <= n; i++)
        root[i] = i;
    for( int i = 1; i <= m; i++)
        scanf("%d%d%d", &road[i].be, &road[i].en, &road[i].dis);
    sort( road+1, road+m+1, cmp);   //對輸入的數據進行排序
    sum = kruscal();
    if(ans == n-1)
        cout << sum << endl;
    else
        cout << "orz" << endl;
    return 0;
}

能力有限,有錯誤麻煩指出,萬分感謝。

最小生成樹——Kruscal(克魯斯卡爾算法)