The Unique MST

The Unique MST Time Limit:1000MS     Memory Limit:10000KB     64bit IO Format:%I64d & %I64u

Submit Status

Description

Given a connected undirected graph, tell if its minimum spanning tree is unique.

Definition 1 (Spanning Tree): Consider a connected, undirected graph G = (V, E). A spanning tree of G is a subgraph of G, say T = (V', E'), with the following properties:
1. V' = V.
2. T is connected and acyclic.

Definition 2 (Minimum Spanning Tree): Consider an edge-weighted, connected, undirected graph G = (V, E). The minimum spanning tree T = (V, E') of G is the spanning tree that has the smallest total cost. The total cost of T means the sum of the weights on all the edges in E'.

Input

The first line contains a single integer t (1 <= t <= 20), the number of test cases. Each case represents a graph. It begins with a line containing two integers n and m (1 <= n <= 100), the number of nodes and edges. Each of the following m lines contains a triple (xi, yi, wi), indicating that xi and yi are connected by an edge with weight = wi. For any two nodes, there is at most one edge connecting them.

Output

For each input, if the MST is unique, print the total cost of it, or otherwise print the string 'Not Unique!'.

Sample Input

2
3 3
1 2 1
2 3 2
3 1 3
4 4
1 2 2
2 3 2
3 4 2
4 1 2

Sample Output

3
Not Unique!

也是最小生成树,问题是这个最小生成树的和,是不是可以由两条不同的路得到
问题就转换成了求次小生成树的问题,看两个是否相等
#include<iostream>
#include<cstring>

using namespace std;

#define N 110
#define INF 0xfffffff

int n, maps[N][N], dist[N], pre[N], vis[N], Max[N][N], use[N][N];

void init()
{
    memset(vis, 0, sizeof(vis));  // 判断下标是否已经在树上
    memset(Max, 0, sizeof(Max));  // 求次小生成树的时候,要减去一条最大边加上一条最大边,还是保证每一个都联通,Max[i][j]数组存从i到j的已经在树上的联通路j到k, k到i两条路上边权值最大的一个
    memset(pre, 0, sizeof(pre));  // pre存下标是通过哪个点连到路上的
    memset(use, 0, sizeof(use));  // use从从i到j边权值是否被最小生成树用到

    for(int i = 1; i <= n; i++)
    {
        dist[i] = 0;
        for(int j = 1; j <= n; j++)
            maps[i][j] = maps[j][i] = INF;
        maps[i][i] = 0;
    }

}  //  初始化

int prim()
{
    int s = 1;
    vis[s] = 1;
    dist[s] = 0;
    int ans = 0;

    for(int i = 1; i <= n; i++)
        dist[i] = maps[i][s], pre[i] = s;   // 从s点开始, s点先到树上

    for(int i = 1; i < n; i++)
    {
        int index, Min = INF;

        for(int j = 1; j <= n; j++)
            if(!vis[j] && dist[j] < Min)
                Min = dist[j], index = j;  // 找当前连到树上所需边权值最小的点

        vis[index] = 1;
        ans += Min;  // 最小值连树,边权值ans总和加
        use[index][pre[index]] = use[pre[index]][index] = 1;  // 表示这个边权值以被最小生成树用,求次小生成树的时候不能用啦

        for(int j = 1; j <= n; j++)
        {
            if(vis[j] && index != j)
                Max[j][index] = Max[index][j] = max(Max[j][pre[index]], dist[index]); 

       // 把可能更新的全更新了,Max找最大的从j到index的路,在j到index的前一点的最大值和index连到pre【index】上找
if(!vis[j] && dist[j] > maps[j][index]) dist[j] = maps[j][index], pre[j] = index; // 更新最短路 } } return ans; } int MST(int sum) { int ans = INF; for(int i = 1; i <= n; i++) { for(int j = i+1; j <= n; j++) { if(!use[i][j] && maps[i][j] != INF) ans = min(ans, sum - Max[i][j] + maps[i][j]); // 找次小生成树,减去最小生成树上i到j最大的边,加上i到j的边权值,联通i,j。min是找较小的 } } return ans; } int main() { int t, m, x, y, w; cin >> t; while(t--) { cin >> n >> m; init(); while(m--) { cin >> x >> y >> w; maps[x][y] = maps[y][x] = w; } int num1 = prim(); int num2 = MST(num1); if(num1 != num2) cout << num1 << endl; // 如果最小生成树和次小生成树不等,就输出唯一的最小生成树的边权值之和,否则输出Not Unique! else cout << "Not Unique!" << endl; } return 0; }
让未来到来 让过去过去
原文地址:https://www.cnblogs.com/Tinamei/p/4680237.html