1. 程式人生 > >Kruskal演算法求最小生成樹-演算法設計與分析實驗3

Kruskal演算法求最小生成樹-演算法設計與分析實驗3

題目: 求如圖所示,用kruskal演算法求下面圖的最小生成樹:

話不多說,程式如下:

#include<iostream>
#include<stdlib.h>
#define N 7
using namespace std;
typedef struct _node{
    int val;
    int start;
    int end;
}Node;
Node V[N];
int cmp(const void *a, const void *b)
{
    return (*(Node *)a).val - (*(Node*)b).val;
}
int edge[N][3] = {  { 0, 1, 3 },
                    { 0, 4, 1 }, 
                    { 1, 2, 5 }, 
                    { 1, 4, 4 },
                    { 2, 3, 2 }, 
                    { 2, 4, 6 }, 
                    { 3, 4, 7} 
                    };

int father[N] = { 0, };
int cap[N] = {0,};

void make_set()              //初始化集合,讓所有的點都各成一個集合,每個集合都只包含自己
{
    for (int i = 0; i < N; i++)
    {
        father[i] = i;
        cap[i] = 1;
    }
}

int find_set(int x)              //判斷一個點屬於哪個集合,點如果都有著共同的祖先結點,就可以說他們屬於一個集合
{
    if (x != father[x])
     {                              
        father[x] = find_set(father[x]);
    }     
    return father[x];
}                                  

void Union(int x, int y)         //將x,y合併到同一個集合
{
    x = find_set(x);
    y = find_set(y);
    if (x == y)
        return;
    if (cap[x] < cap[y])
        father[x] = find_set(y);
    else
    {
        if (cap[x] == cap[y])
            cap[x]++;
        father[y] = find_set(x);
    }
}

int Kruskal(int n)
{
    int sum = 0;
    make_set();
    for (int i = 0; i < N; i++)//將邊的順序按從小到大取出來
    {
        if (find_set(V[i].start) != find_set(V[i].end))     //如果改變的兩個頂點還不在一個集合中,就併到一個集合裡,生成樹的長度加上這條邊的長度
        {
            Union(V[i].start, V[i].end);  //合併兩個頂點到一個集合
            sum += V[i].val;
        }
    }
    return sum;
}
int main()
{
    for (int i = 0; i < N; i++)   //初始化邊的資料,在實際應用中可根據具體情況轉換並且讀取資料,這邊只是測試用例
    {
        V[i].start = edge[i][0];
        V[i].end = edge[i][1];
        V[i].val = edge[i][2];
    }
    qsort(V, N, sizeof(V[0]), cmp);
    cout << Kruskal(0)<<endl;
    return 0;
}

執行結果如下:

從圖中也可以看出,最小權值是: 1+3+5+2 = 11,那麼這個實驗的第一小題就是這樣。