F - 資料結構實驗之圖論六:村村通公路

笑著找bug發表於2020-11-25

Description

當前農村公路建設正如火如荼的展開,某鄉鎮政府決定實現村村通公路,工程師現有各個村落之間的原始道路統計資料表,表中列出了各村之間可以建設公路的若干條道路的成本,你的任務是根據給出的資料表,求使得每個村都有公路連通所需要的最低成本。

Input

連續多組資料輸入,每組資料包括村落數目N(N <= 1000)和可供選擇的道路數目M(M <= 3000),隨後M行對應M條道路,每行給出3個正整數,分別是該條道路直接連通的兩個村莊的編號和修建該道路的預算成本,村莊從1~N編號。

Output

輸出使每個村莊都有公路連通所需要的最低成本,如果輸入資料不能使所有村莊暢通,則輸出-1,表示有些村莊之間沒有路連通。

Sample

Input
5 8
1 2 12
1 3 9
1 4 11
1 5 3
2 3 6
2 4 9
3 4 4
4 5 6

Output
19

#include <iostream>
#include <bits/stdc++.h>

using namespace std;

//並查集
struct node
{
    int u,v,w;
}edge[1010];

int parent[1010];
int n,m;

//用於排序
bool cmp(node a,node b)
{
    return a.w < b.w;
}

//初始化
void UFset()
{
    for(int i=1;i<=n;i++)
        parent[i] = -1;
}

//查詢並返回結點 x 所屬集合的根節點
int Find_root(int x)
{
    //查詢s位置,找到根
    int i;
    for(i=x; parent[i]>=0; i=parent[i]);
    //優化方案: 壓縮路徑
    while(i!=x)
    {
        int tmp = parent[x];
        parent[x] = i;
        x = tmp;
    }
    return i;
}

//將兩個不同集合的元素合併
//使兩個集合中任兩個元素都聯通
void Union(int R1,int R2)
{
    int r1 = Find_root(R1);
    int r2 = Find_root(R2);
    int t = parent[r1] + parent[r2];
    if(parent[r1] > parent[r2])
    {
        parent[r1] = r2;
        parent[r2] = t;
    }
    else
    {
        parent[r2] = r1;
        parent[r1] = t;
    }
}

int Kruskal()
{
    int sum = 0;//權值
    int num = 0;//已選邊數
    int u,v;
    UFset();
    sort(edge,edge+m,cmp);
    for(int i=0;i<m;i++)
    {
        u = edge[i].u;
        v = edge[i].v;
        if(Find_root(u) != Find_root(v))
        {
            sum += edge[i].w;
            num++;
            Union(u,v);
        }
        if(num >= n-1)
            return sum;
    }
    return -1;
}

int main()
{
    ios::sync_with_stdio(false);

    while(cin>>n>>m)
    {
        for(int i=0; i<m; i++)
            cin>>edge[i].u>>edge[i].v>>edge[i].w;
        cout<<Kruskal()<<endl;
    }
    return 0;
}

相關文章