POJ1679The Unique MST(次小生成树)

题目

本题的思路就是判断一个图的最小生成树和次小生成树的权值是否一样,也就是最小生成树是否唯一。先跑一遍prim求出最小生成树后,再将每一条不在最小生成树里的边加入MST,然后删掉形成的环上权值最大的边,最后判断一下就可以。

qq学长的博客:https://blog.csdn.net/qq_28954601/article/details/71102139

别的大佬的:https://www.cnblogs.com/bianjunting/p/10829212.html

我的code:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cmath>
#include <string>
#include <vector>
#include <stack>
#include <map>
#include <sstream>
#include <cstring>
#include <set>
#include <cctype>
#include <bitset>
#define IO                       \
    ios::sync_with_stdio(false); \
    // cin.tie(0);                  \
    // cout.tie(0);
using namespace std;
typedef long long LL;
const int maxn = 1e2 + 10;
const int maxm = 1e5 + 10;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int inf = 0x3f3f3f3f;
const LL mod = 11092019;
int dis[8][2] = {0, 1, 1, 0, 0, -1, -1, 0, 1, -1, 1, 1, -1, 1, -1, -1};
int n, m, e[maxn][maxn];
int Max[maxn][maxn]; // 区间内权值最大的边权
int lowc[maxn]; // 生成树到每个点的最短距离
int pre[maxn]; // 该点是由哪个店 "扩展" 进入 MST 的
bool used[maxn][maxn]; // 当前边有没有被使用过
bool vis[maxn];      // prim 算法 标记已经加入 MST 的点
void init(int n)
{
    memset(e, inf, sizeof e);
    for (int i = 1; i <= n; i++)
        e[i][i] = 0;
}
int prim(int n)
{
    int ans = 0;
    memset(vis, false, sizeof vis);
    memset(used, false, sizeof used);
    memset(Max, 0, sizeof Max);
    vis[1] = true;
    pre[1] = -1; // 1 没有任何点引入
    lowc[1] = 0;
    for (int i = 2; i <= n; i++)
        lowc[i] = e[1][i], pre[i] = 1;// 一开始每个点都是由 1 号点引入的
    for (int i = 1; i < n; i++)
    {
        int minc = inf;
        int p;
        for (int j = 1; j <= n; j++)
        {
            if (!vis[j] && lowc[j] < minc)
            {
                p = j;
                minc = lowc[j];
            }
        }
        ans += minc;
        vis[p] = true;
        used[p][pre[p]] = used[pre[p]][p] = true;
        for (int j = 1; j <= n; j++)
        {
            if (vis[j] && j != p) // 对于已经在 MST 里面的点
            {
                Max[j][p] = Max[p][j] = max(Max[j][pre[p]], lowc[p]); // 更新 i->j 上的最大权值 
            }
            if (!vis[j] && lowc[j] > e[p][j])// 更新 MST 到各点的距离
            {
                pre[j] = p;
                lowc[j] = e[p][j];
            }
        }
    }
    return ans;
}
int main()
{
#ifdef ONLINE_JUDGE
#else
    freopen("in.txt", "r", stdin);
    // freopen("out.txt", "w", stdout);
#endif
    IO;
    int T, a, b, c;
    scanf("%d", &T);
    while (T--)
    {
        scanf("%d %d", &n, &m);
        init(n);
        for (int i = 0; i < m; i++)
        {
            scanf("%d %d %d", &a, &b, &c);
            e[a][b] = e[b][a] = c;
        }
        int ans = prim(n);
        int temp = inf;
        for (int i = 1; i <= n; i++)
            for (int j = i + 1; j <= n; j++)
                if (e[i][j] != inf && !used[i][j]) // 用每个不在 MST 更新temp
                    temp = min(temp, ans + e[i][j] - Max[i][j]);
        if (temp == ans)
            printf("Not Unique!\n");
        else
            printf("%d\n", ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_44115065/article/details/106126595