1. 程式人生 > 其它 >acwing 859. Kruskal演算法求最小生成樹

acwing 859. Kruskal演算法求最小生成樹

目錄

題目傳送門

題目描述

給定一個 n 個點 m 條邊的無向圖,圖中可能存在重邊和自環,邊權可能為負數。

求最小生成樹的樹邊權重之和,如果最小生成樹不存在則輸出 impossible

給定一張邊帶權的無向圖 G=(V,E),其中 V 表示圖中點的集合,EE 表示圖中邊的集合,n=|V|,m=|E|。

由 V 中的全部 n 個頂點和 E 中 n−1 條邊構成的無向連通子圖被稱為 G 的一棵生成樹,其中邊的權值之和最小的生成樹被稱為無向圖 G 的最小生成樹。

輸入格式

第一行包含兩個整數 n 和 m。

接下來 m 行,每行包含三個整數 u,v,w,表示點 u 和點 v 之間存在一條權值為 w 的邊。

輸出格式

共一行,若存在最小生成樹,則輸出一個整數,表示最小生成樹的樹邊權重之和,如果最小生成樹不存在則輸出 impossible

資料範圍

1≤n≤10^5
1≤m≤2∗10^5
圖中涉及邊的邊權的絕對值均不超過 10001000。

輸入樣例:

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

輸出樣例:

6

Kruskal最小生成樹(適用於稀疏圖)

分析

prim使用鄰接表,適用於稠密圖(點的個數比較小的情況)

演算法步驟

  • 將所有邊按照權重排序
  • 從小到大列舉所有邊
    • 如果某條邊的兩個端點不連通的劃(用並查集判斷是否連通),就把這條邊加入到最小生成樹,(並查集中連線這兩個點)
  • 最後如果邊的數量小於n-1,說明不連通,否則輸出最小生成樹長度

這裡使用結構題存邊

struct Edge
{
    int a, b, w;
    bool operator< (const Edge W)const
    {
        return w < W.w;
    }
}edges[M];

程式碼

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

using namespace std;
const int  N = 100010, M = 200010, INF = 0x3f3f3f3f;
int n, m;
int p[N]; // 並查集使用

struct Edge
{
    int a, b, w;
    bool operator< (const Edge W)const
    {
        return w < W.w;
    }
}edges[M];

int find(int x)
{
    if(p[x] != x) p[x] = find(p[x]);
    return p[x];
}

int kruskal()
{
    sort(edges, edges+m);
    int res = 0, cnt = 0; // cnt表示加入的邊數
    for(int i = 0; i < m; i++)
    {
        int a = edges[i].a, b = edges[i].b, w = edges[i].w;
        int fa = find(a), fb = find(b);
        if(fa != fb)
        {
            p[fa] = fb;
            res += w;
            cnt++;
        }
    }

    if(cnt < n-1) return INF;
    else    return res;

}

int main()
{
    scanf("%d%d", &n, &m);
    for(int i = 0; i < m; i++)
    {
        int a, b, w;
        scanf("%d%d%d", &a, &b, &w);
        edges[i] = {a, b, w};
    }

    for(int i = 1; i <= n; i++) p[i] = i; // 初始化並查集
    int  res = kruskal();
    if(res == INF) printf("impossible\n");
    else printf("%d\n", res);
    return 0;
}

時間複雜度

參考文章