克魯斯卡爾算法(Kruskal)圖的最小生成樹

算法競賽中常用的算法,求圖的最小生成樹
過程:
對邊集排序,
選取最小邊,將連接的節點放到一個集合中
選取次小的邊,當邊連接的定點不在同一個集合中時,合併集合。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
int u[200],v[200];//最大有200條邊,每條邊的兩個節點的位置
float w[200];//每條邊的權值
int f[200];//200個邊的父節點,並查集使用
int node_num,side_num;//節點個數,邊的個數
int r[200];//儲存排序後,第小的邊的編號
queue<int> side;
void build_map()//建立圖
{
    int i;
    i = 0;
    printf("輸入節點個數:\n");
    scanf("%d", &node_num);//輸入節點個數
    printf("輸入邊的信息:節點1,節點2,權重 \n");
    while(1)
    {
        int a, b;
        float c;
        if (scanf("%d,%d,%f", &a, &b, &c) != 3) break;//輸入該邊的兩個定點以及該邊的權重
        u[i] = a;
        v[i] = b;
        w[i] = c;
        i++;
    }
    side_num = i;//統計邊的個數
}
int cmp(int i, int j)
{
    return w[i] < w[j];
}
int find(int x)
//並查集,用於判斷是否在同一個集合
//這是這些天遇到的第二個暴力,簡潔,優美的算法了
{
    return f[x] == x ? x : find(f[x]);
}
int main()
{
    build_map();
    for (int i = 0; i < node_num; i++)
    {
        f[i] = i;//初始化並查集
    }
    for (int i = 0; i < side_num; i++)
    {
        r[i] = i;//初始化邊的編號
    }
    sort(r, r + side_num, cmp);//對邊按照順序排列
    for (int i = 0; i < side_num; i++)
    {
        int k = r[i];
        int x = find(u[k]);
        int y = find(v[k]);
        if (x != y)//若兩個節點不在同一個集合裏,則合併
        {
            f[x] = y;
            side.push(r[i]);
        }
    }
    printf("邊集爲:\n");
    while (!side.empty())//輸出邊集
    {
        int m = side.front();
        side.pop();
        printf("%d,%d\n", u[m], v[m]);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章