Agri-Net POJ - 1258 (最小生成树)

题意:有n个农场,已知这n个农场都互相相通,有一定的距离,现在每个农场需要装光纤,问怎么安装光纤能将所有农场都连通起来,并且要使光纤距离最小,输出安装光纤的总距离。任意两个村庄之间的距离小于 100,000.

分析:连通+距离最小 = 最小生成树
Prim算法适用于稠密图, Kruskal适用于稀疏图

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
typedef long long LL;
const int N = 110, INF = 0x3f3f3f3f;
int n, m, g[N][N], f[N];
struct T {
    int u, v, w;
    T(int a = 0, int b = 0, int c = 0) : u(a), v(b), w(c) {}
    bool operator<(const T& r) const { return w < r.w; }
} t[N * N];

int dis[N];
bool st[N];
int prim() {
    memset(dis, 0x3f, sizeof(dis));
    memset(st, 0, sizeof(st));
    int ans = 0;
    for (int i = 1; i <= n; i++) {
        int u = -1;
        for (int j = 1; j <= n; j++)
            if (!st[j] && (u == -1 || dis[j] < dis[u]))
                u = j;
        if (i > 1 && dis[u] == INF) return -1;
        if (i > 1) ans += dis[u];
        for (int j = 1; j <= n; j++)
            if (dis[j] > g[u][j]) dis[j] = g[u][j];
        st[u] = 1;
    }
    return ans;
}

int find(int u) {
    return u == f[u] ? u : f[u] = find(f[u]);
}
int kruskal() {
    sort(t + 1, t + 1 + m);
    for (int i = 0; i <= n; i++) f[i] = i;
    int ans = 0, cnt = 0;
    for (int i = 1; i <= m; i++) {
        int fu = find(t[i].u), fv = find(t[i].v);
        if (fu != fv) f[fu] = fv, ans += t[i].w, cnt++;
        if (cnt == n - 1) break;
    }
    return cnt==n-1?ans:-1;
}
int main() {
    while (~scanf("%d", &n)) {
        m=0;
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                scanf("%d", &g[i][j]);
                t[++m] = T(i, j, g[i][j]);
            }
        }
        // printf("%d\n", prim());
        printf("%d\n", kruskal());
    }
    return 0;
}
posted @ 2023-03-28 14:57  HelloHeBin  阅读(20)  评论(0)    收藏  举报