最小生成树 —— Kruskal算法 & Prim算法模板

// Prim 适用于稠密图,时间复杂度O(n^2)
#include <iostream>
#include <cstdio>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;

const int INF = 0x3f3f3f3f;

void Prim() {
/*
    G = (V, E)是连通带权无向图, V = {0, 1, ... n-1} 是顶点集, E是边集.
    求最小生成树 T = (S, e),  其中 S = V
*/
    int n;  // 点数
    scanf("%d", &n);
    vector<vector<int> > G(n, vector<int>(n, INF));
    int u, v, value;
    while(~scanf("%d %d %d", &u, &v, &value)) {
        G[u][v] = value;
        G[v][u] = value;
    }
    int cost = 0;
    vector<int> lowcost = G[0];   // S -> S-V的“距离”
    vector<bool> vis(n, false);
    vis[0] = true;
    int size_S = 1;
    while(size_S < n) {   // O(n)
        int lowc = INF, k;
        for(int i=0; i<n; ++i) {      // O(n)
            if(!vis[i] && lowcost[i] < lowc) {
                lowc = lowcost[i];
                k = i;
            }
        }
        vis[k] = true;
        cost += lowcost[k];
        ++size_S;
        for(int i=0; i<n; ++i) {        // O(n)
            if(!vis[i] && G[k][i] < lowcost[i])
                lowcost[i] = G[k][i];
        }
    }
    cout << "Prim: " << cost << endl;
}

// =========================================
struct Edge {
    int u;
    int v;
    int value;
    Edge(int u = -1, int v = -1, int value = -1) : u(u), v(v), value(value) {}
    friend bool operator < (const Edge&e1, const Edge& e2) { return e1.value > e2.value; }
};
int getf(vector<int>& f, int x) {
    if(f[x] == x) return x;
    else f[x] = getf(f, f[x]);
    return f[x];
}
bool merge(vector<int>& f, int x, int y) {
    int fx = getf(f, x);
    int fy = getf(f, y);
    if(fx == fy) return false;
    f[fy] = fx;
    return true;
}
void Kruskal() {
    int n;
    scanf("%d", &n);
    
    priority_queue<Edge> pq; //堆存边
    int u, v, value;
    while(~scanf("%d %d %d", &u, &v, &value)) 
        pq.push(Edge(u, v, value));

    // 并查集初始化
    vector<int> f(n);  
    for(int i=0; i<n; ++i) f[i] = i; 

    int tot = 0, cost = 0;
    while(!pq.empty() && tot < n-1) {
        // 不断选最短的判断, 选n-1条
        Edge e = pq.top();
        pq.pop();
        if(merge(f, e.u, e.v)) {
            ++tot;
            cost += e.value;
        }
    }
    cout << "Kruskal: " << cost << endl;

}



int main()
{
    Prim();   // O(n^2)  与边数无关, 对稠密图友好
    cout << " =============== \n";
    Kruskal();      // O(MlogM),  对定点多但边少的稀疏图友好
}
Input:
6
0 1 6
0 2 1
0 3 5
1 2 5
1 4 3
2 3 5
2 5 4
3 5 2
4 5 6

Output:
15

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值