最小生成树MST

本文介绍了两种经典的图论算法——Prim和Kruskal算法,用于解决最小生成树问题。在公路村村通的实例中,通过这两种算法找出连接所有村落的最低成本路径。Prim算法利用优先队列动态维护最小生成树,而Kruskal算法则通过并查集避免形成环路。文章提供了两种算法的C++实现,并给出了样例输入和输出。
摘要由CSDN通过智能技术生成

最小生成树:
1.prim算法:(点集A:最小生成树的点;点集B:最小生成树外的点;每次寻找树中到树外的点,将树外的点加入树中)
2.kruskal算法:(将所有边集按升序排序;每次寻找不形成回路的边)
例题:公路村村通 (15 分)(选自PTA)
现有村落间道路的统计数据表中,列出了有可能建设成标准公路的若干条道路的成本,求使每个村落都有公路连通所需要的最低成本。

输入格式:
输入数据包括城镇数目正整数N(≤1000)和候选道路数目M(≤3N);随后的M行对应M条道路,每行给出3个正整数,分别是该条道路直接连通的两个城镇的编号以及该道路改建的预算成本。为简单起见,城镇从1到N编号。

输出格式:
输出村村通需要的最低成本。如果输入数据不足以保证畅通,则输出−1,表示需要建设更多公路。

输入样例:

6 15
1 2 5
1 3 3
1 4 7
1 5 4
1 6 2
2 3 4
2 4 6
2 5 2
2 6 6
3 4 6
3 5 1
3 6 1
4 5 10
4 6 8
5 6 3

输出样例:

12

prim算法实现:

#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
#define inf 0x3f3f3f3f
const int N = 1010;
struct Edge {
    int v, w;
    Edge(int _v, int _w) : v(_v), w(_w) {}
    bool operator<(const Edge& edge)const {
        return w > edge.w;
    }
};
vector<Edge>E[N];
priority_queue<Edge>pq;
int dis[N], vis[N];
int prim(int n) {
    memset(dis, inf, sizeof(dis));
    memset(vis, 0, sizeof(vis));
    Edge t(1, 0); pq.push(t);
    int ans = 0, used = 0;
    while (!pq.empty() && used < n) {
        do {
            t = pq.top(); pq.pop();
        } while (!pq.empty() && vis[t.v]);
        if (!vis[t.v]) {
            vis[t.v] = 1;
            ans += t.w;
            used++;
            for (int i = 0; i < E[t.v].size(); i++) {
                int vv = E[t.v][i].v;
                if (!vis[vv]) {
                    int ww = E[t.v][i].w;
                    if (dis[vv] > ww) {
                        dis[vv] = ww;
                        pq.push({vv, ww});
                    } 
                }
            }
        }
    }
    if (used < n) {
        return -1;
    }
    return ans;
}
int main(int argc, char** argv) {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    int n, m;
    cin >> n >> m;
    for (int i = 0; i < m; i++) {
        int v1, v2, ww;
        cin >> v1 >> v2 >> ww;
        E[v1].push_back({v2, ww});
        E[v2].push_back({v1, ww});
    }
    cout << prim(n) << endl;
    return 0;
}

kruskal算法实现:

#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
const int N = 1010;
struct Edge {
    int v, to, w;
    Edge() {}
    Edge(int _v, int _to, int _w) : v(_v), to(_to), w(_w) {}
    bool operator<(const Edge& edge)const {
        return w < edge.w;
    }
};
vector<Edge>E;
int fa[N];
int Find(int x) {
    return fa[x] == x ? x : fa[x] = Find(fa[x]);
}
int Union(int a, int b) {
    a = Find(a); b = Find(b);
    fa[a] = b;
    return a != b;
}
int main(int argc, char** argv) {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; i++) {
        fa[i] = i;
    }
    for (int i = 0; i < m; i++) {
        int v1, v2, ww;
        cin >> v1 >> v2 >> ww;
        E.push_back({v1, v2, ww});
    }
    sort(E.begin(), E.end());
    int ans = 0, used = 0;
    for (int i = 0; i < m; i++) {
        if (Union(E[i].v, E[i].to)) {
            ans += E[i].w;
            used++;
        }
    }
    if (used == n - 1) {
        cout << ans << endl;
    }
    else {
        cout << "-1" << endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值