PKU 1679 The Unique MST

判断最小生成树是否唯一,可以证明如果MST不唯一,必然是由于有两条边的权相等(反过来不成立),那么在第一次求MST时可以标记这类边,然后逐一去掉重新求MST,看是否和之前的相等。

/*
    判断最小生成树是否唯一, kruskal 
*/
# include <stdio.h>
# include <stdlib.h>

# define N 105
# define M 5005

int n, m;
int p[N];
int r[M], u[M], v[M], w[M];
char h[M], ud[M], pi[M];

int find(int x) {return x==p[x] ? x:(p[x] = find(p[x]));}
int cmp(const void *x, const void *y)
{
    int xx = *(int *)x, yy = *(int *)y;
    return w[xx] - w[yy];
}

int kruskal(char bj)
{
    int i, ret = 0, e, x, y;
    
    for (i = 1; i <= n; ++i) p[i] = i;
    for (i = 1; i <= m; ++i) if (h[e = r[i]])
    {
        x = find(u[e]), y = find(v[e]);
        if (x != y)
        {
            p[x] = y;
            ret += w[e];
            if (!bj && pi[e]) ud[e] = 1;
        }
    }
    
    return ret;
}

void solve(void)
{
    int i, ans;
    
    for (i = 1; i <= m; ++i)
    {
        pi[i] = ud[i] = 0;
        r[i] = i, h[i] = 1;
    }    
    qsort(r+1, m, sizeof(r[0]), cmp);
    for (i = 2; i <= m; ++i) if (w[r[i]] == w[r[i-1]])
        pi[r[i]] = pi[r[i-1]] = 1;
    
    ans = kruskal(0);
    for (i = 1; i <= m; ++i) if (ud[i])
    {
        h[i] = 0;
        if (ans == kruskal(1))
        {
            puts("Not Unique!");
            return ;
        }
        h[i] = 1;
    }
    printf("%d\n", ans);
}

void init(void)
{
    int i;
    
    scanf("%d%d", &n, &m);
    for (i = 1; i <= m; ++i)
        scanf("%d%d%d", &u[i], &v[i], &w[i]);
}

int main()
{    
    int T;
    
    scanf("%d", &T);
    while (T--)
    {
        init();
        solve();
    }
    
    return 0;
}

COJ 的题目排列怎么乱了,以前的题很多都找不到了,包括有一道(幻想乡的路?)也是要判断MST是否唯一。

原文地址:https://www.cnblogs.com/JMDWQ/p/2634228.html