POJ1679-The Unique MST(次小生成树+最小瓶颈路 )

本文介绍了一种通过求解次小生成树来判断给定图的最小生成树是否唯一的算法。利用Kruskal算法找到最小生成树后,再通过深度优先搜索(DFS)预处理最小瓶颈路径,最后对比最小生成树与次小生成树的权值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接

http://poj.org/problem?id=1679

题意

给定求一张图,判断它的最小生成树是否唯一

思路

只需求出该图的次小生成树,并且判断最小生成树和次小生成树权值和是否相同即可
那么问题就转化成了求次小生成树:先求出最小生成树,然后枚举剩下的m - n +1条边, 将其中一条边(u, v)加入MST中,这样必定u->v之间会形成回路,根据最小生成树的回路性质,回路中权值最大的那条边必定不在最小生成树中,因此我们只需删除MST中u->v权值最大的那条边,即u->v之间的最小瓶颈路
于是可以考虑预处理出任意一对结点之间的最小瓶颈路,可以知道任意一对结点u->v的最小瓶颈路就为MST上u->v的路径。因此,只需求出原图的MST,并且DFS将其转化为有根树并求任意一对结点之间的最小瓶颈路即可

代码

#include <iostream>
#include <cstring>
#include <stack>
#include <vector>
#include <set>
#include <map>
#include <cmath>
#include <queue>
#include <sstream>
#include <iomanip>
#include <fstream>
#include <cstdio>
#include <cstdlib>
#include <climits>
#include <deque>
#include <bitset>
#include <algorithm>
using namespace std;

#define PI acos(-1.0)
#define LL long long
#define PII pair<int, int>
#define PLL pair<LL, LL>
#define mp make_pair
#define IN freopen("in.txt", "r", stdin)
#define OUT freopen("out.txt", "wb", stdout)
#define scan(x) scanf("%d", &x)
#define scan2(x, y) scanf("%d%d", &x, &y)
#define scan3(x, y, z) scanf("%d%d%d", &x, &y, &z)
#define sqr(x) (x) * (x)
#define pr(x) cout << #x << " = " << x << endl
#define lc o << 1
#define rc o << 1 | 1
#define pl() cout << endl

const int maxn = 10005;
int n, m, p[maxn], r[maxn];
bool use[maxn];
vector<PII> G[105];
struct Edge {
    int u, v, w;
    Edge(int a, int b, int c) : u(a), v(b), w(c) {

    }
    Edge() {

    }
} E[maxn];

int find(int x) {
    return p[x] == x ? x : p[x] = find(p[x]);
}

bool cmp(Edge x, Edge y) {
    return x.w < y.w;
}

int kruskal() {
    for (int i = 1; i <= n; i++) p[i] = i;
    int ans = 0;
    sort(E, E + m, cmp);
    for (int i = 0; i < m; i++) {
        int x = E[i].u, y = E[i].v;
        x = find(x);
        y = find(y);
        if (x != y) {
            ans += E[i].w;
            p[x] = y;
            use[i] = 1;
            G[E[i].u].push_back(mp(E[i].v, E[i].w));
            G[E[i].v].push_back(mp(E[i].u, E[i].w));
        }
    }
    return ans;
}

const int maxnode = 105;
int f[maxnode][maxnode], x;
void dfs(int u, int v, int MAX, int w) {
    if (v > 0) f[x][u] = max(MAX, w);
    for (int i = 0; i < G[u].size(); i++) {
        int son = G[u][i].first;
        if (son == v) continue;
        dfs(son, u, f[x][u], G[u][i].second);
    }
}

int main() {
    int T;
    scan(T);
    while (T--) {
        scan2(n, m);
        memset(f, 0, sizeof(f));
        memset(use, 0, sizeof(use));
        for (int i = 0; i < 105; i++) G[i].clear();
        for (int i = 0; i < m; i++) {
            int x, y, z;
            scan3(E[i].u, E[i].v, E[i].w);
        }
        int mst = kruskal();
        for (int i = 1; i <= n; i++) {
            x = i;
            dfs(i, -1, 0, 0);
        }
        bool flag = true;
        for (int i = 0; i < m; i++) {
            if (use[i]) continue;
            int from = E[i].u, to = E[i].v;
            int mst_ans = max(f[from][to], f[to][from]);
            if (mst_ans == E[i].w) {
                flag = false;
                break;
            }
        }
        if (!flag) puts("Not Unique!");
        else printf("%d\n", mst);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值