POJ 1679 The Unique MST (次小生成树kruskal算法)

The Unique MST

时间限制: 10 Sec  内存限制: 128 MB
提交: 25  解决: 10
[提交][状态][讨论版]

题目描述

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'.

输入

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 ,1 <= m <= 10000), 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 may be more than one edge to connect them.

输出

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

样例输入

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

样例输出

3
Not Unique!



题意:给一个无向图,判断这个图的最小生成树MST是否是唯一的。如果是唯一的,输出最小生成树的值,如果不是唯一的,输出“Not Unique!”

思路:kruskal的应用。详细思路与prim版相似,而且时间空间复杂度都得到了一些优化。

kruskal算法:把所有的边都排个序,从大到小取出,若取出的这条边的两个端点已经连通(用并查集),则换下一条边,n的顶点用n-1条边就可以相连,循环直到n-1条边。

本题:在找最小生成树(mst)的同时,把选中的边(是第几条)都存下来。再进行多次kruskal算法,每次模拟删除一条边,寻找一条新的边,得到边权和为mst2,判断mst==mst2?即可。

#include <iostream>
#include<string>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
int n, m;
int pre[105];
int Rank[105];
int mst_e[105];
struct node
{
    int u, v, w;
};
bool cmp(node x, node y)
{
    return x.w < y.w;
}
void init()//初始化
{
    int i;
    for (i = 1; i <= n; i++) pre[i] = i;
    memset(Rank, 0, sizeof(Rank));
}
int find(int x)//找根
{
    if (pre[x] == x) return x;
    return pre[x] = find(pre[x]);
}
void unite(int x, int y)//压缩合并
{
    if (Rank[x] < Rank[y]) pre[x] = y;
    else
    {
        pre[y] = x;
        if (Rank[x] == Rank[y]) Rank[x]++;
    }
}
int main()
{
    int t;
    cin >> t;
    while (t--)
    {
        cin >> n >> m;
        init();
        node a[10005];
        int i;
        for (i = 1; i <= m; i++)
        {
            cin >> a[i].u >> a[i].v >> a[i].w;
        }
        sort(a + 1, a + 1 + m, cmp);
        int mst = 0;
        int k = 1;
        for (i = 1; i <= m; i++)//第一次kruskal算法
        {
            int x = find(a[i].u);
            int y = find(a[i].v);
            if (x != y)
            {
                unite(x, y);
                mst = mst + a[i].w;
                mst_e[k++] = i;//  记录下MST的边。
            }
        }
        int edge_num = k-1;
        bool uni = 1;//记录是不是唯一
        int mst2, num;
        for (k =1; k <=edge_num; k++)
        {//遍历每一条MST里的边,一次次模拟删除
            init();//每进行一次kruskal算法,就初始化一次
            mst2 = 0;
            num = 0;
            for (i = 1; i <= m; i++)
            {
                if (i == mst_e[k]) continue;//模拟删除
                int x = find(a[i].u);
                int y = find(a[i].v);
                if (x != y)
                {
                    unite(x, y);
                    mst2 = mst2 + a[i].w;
                    num++;
                }
                if (num != edge_num) continue;//边数没达到就继续0
                if (mst2 == mst)
                {
                    uni = 0;
                    break;
                }
            }
            if (uni == 0) break;
        }
        if (uni) cout << mst << endl;
        else cout << "Not Unique!" << endl;
    }
    return 0;
}
原文地址:https://www.cnblogs.com/caiyishuai/p/13271301.html