POJ - The Unique MST(次小生成树)

题目链接:http://poj.org/problem?id=1679
Time Limit: 1000MS Memory Limit: 10000K

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!

Problem solving report:

Description: 给一个图,问其最小生成树是否惟一。
Problem solving: 判断最小生成树是不是唯一的,我们求出次小生成树,和最小生成树比较即可。而次小生成树可由最小生成树换一条边得到。
我们要找次小生成树,一定是每次把不在最小生成树中的边加入一条并把最小生成树中的边删除一条,然后取所有非最小生成树中最小的,即次小生成树。
我们可以先用prim求出最小生成树T,在prim的同时,用一个矩阵Max[i][j]记录在树中连接i-j的路径中权值最大的边。然后枚举所有不在T中的边i-j,加入边i-j,如果加入的边和删除的边的大小是一样的,说明次小生成树的权值和等于最小生成树的权值和,也就是说最小生成树不唯一。

Accepted Code:

//Prim
/* 
 * @Author: lzyws739307453 
 * @Language: C++ 
 */
#include <queue>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
const int MAXN = 105;
const int inf = 0x3f3f3f3f;
bool vis[MAXN],visp[MAXN][MAXN];
int dis[MAXN], pre[MAXN], mp[MAXN][MAXN], Max[MAXN][MAXN];
struct edge {
    int v, w;
    edge() {}
    edge(int v, int w) : v(v), w(w) {}
    bool operator < (const edge &s) const {
        return s.w < w;
    }
};
int prim(int s, int n) {
    priority_queue <edge> Q;
    for (int i = 1; i <= n; i++) {
        vis[i] = 0;
        dis[i] = inf;
    }
    dis[s] = 0;
    Q.push(edge(s, dis[s]));
    int ans = 0;
    while (!Q.empty()) {
        edge u = Q.top();
        Q.pop();
        if (vis[u.v])
            continue;
        vis[u.v] = 1;
        ans += u.w;
        visp[u.v][pre[u.v]] = visp[pre[u.v]][u.v] = true;
        for (int j = 1; j <= n; j++) {
            if (vis[j])
                Max[u.v][j] = Max[j][u.v] = max(Max[j][pre[u.v]], dis[u.v]);
            if (!vis[j] && dis[j] > mp[u.v][j]) {
                pre[j] = u.v;
                dis[j] = mp[u.v][j];
                Q.push(edge(j, dis[j]));
            }
        }
    }
    return ans;
}
int MST(int n, int ans) {
    int min_ = inf;
    for (int i = 1; i <= n; i++)
        for (int j = i + 1; j <= n; j++)
            if (!visp[i][j] && mp[i][j] < inf)
                min_ = min(min_, ans + mp[i][j] - Max[i][j]);
    return min_;
}
int main() {
    int n, m, t;
    scanf("%d", &t);
    while (t--) {
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
                if (i != j)
                    mp[i][j] = inf;
        memset(pre, 0, sizeof(pre));
        memset(visp, 0, sizeof(visp));
        for (int i = 0; i < m; i++) {
            int u, v, w;
            scanf("%d%d%d", &u, &v, &w);
            mp[u][v] = mp[v][u] = w;
        }
        int ans = prim(1, n);
        if (ans != MST(n, ans))
            printf("%d\n", ans);
        else printf("Not Unique!\n");
    }
    return 0;
}
//Kruskal
/* 
 * @Author: lzyws739307453 
 * @Language: C++ 
 */
#include <queue>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
const int MAXN = 105;
const int MAXM = MAXN * MAXN;
const int inf = 0x3f3f3f3f;
bool vis[MAXN];
int Max[MAXN][MAXN];
struct edge {
    int u, v, w;
    bool operator < (const edge &s) const {
        return s.w > w;
    }
}e[MAXM];
int f[MAXN];
vector <int> G[MAXN];
bool cmp(edge a, edge b) {
    return a.w < b.w;
}
int getf(int v) {
    if (f[v] != v)
        return f[v] = getf(f[v]);
    return v;
}
bool merge(int u, int v, int w) {
    int t1 = getf(u);
    int t2 = getf(v);
    if (t1 != t2) {
        f[t1] = t2;
        int siz1 = G[t1].size(), siz2 = G[t2].size();
        for (int j = 0; j < siz1; j++)
            for (int k = 0; k < siz2; k++)
                Max[G[t1][j]][G[t2][k]] = Max[G[t2][k]][G[t1][j]] = w;
        for (int j = 0; j < siz1; j++)
            G[t2].push_back(G[t1][j]);
        return true;
    }
    return false;
}
int Kruskal(int n, int m) {  
    int cnt = 0, count_ = 0;
    for (int i = 1; i <= n; i++) {
        G[i].clear();
        G[i].push_back(i);
        f[i] = i;
    }
    sort(e, e + m);
    for (int i = 0; i < m && count_ < n - 1; i++) {
        if (merge(e[i].u, e[i].v, e[i].w)) {
            count_++;
            cnt += e[i].w;
            vis[i] = true;
        }
    }
    return cnt;
}
int MST(int m, int ans) {
    int min_ = inf;
    for (int i = 0; i < m; i++)
        if (!vis[i])
            min_ = min(min_, ans + e[i].w - Max[e[i].u][e[i].v]);
    return min_;
}
int main() {
    int n, m, t;
    scanf("%d", &t);
    while (t--) {
        memset(vis, 0, sizeof(vis));
        scanf("%d%d", &n, &m);
        for (int i = 0; i < m; i++)
            scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].w);
        int ans = Kruskal(n, m);
        if (ans != MST(m, ans))
            printf("%d\n", ans);
        else printf("Not Unique!\n");
    }
    return 0;
}
全部评论

相关推荐

10-29 16:42
门头沟学院 Java
1.今天什么国标的公司打电话约面试,还得准备ppt,好麻烦,网上查薪资一般,打算拒了,不面了2.字节又复活了,什么安全开发,也不知道怎么样,面一面试试吧,还是挺想去字节的,但好难,随缘吧所以今天没面试
嵌入式的小白:面试前可以好好准备下 1.看看你投递的岗位的岗位描述,分析下是哪个业务线,同使要罗列他们描述中提到的技术点 2.根据1中的两点准备 3.岗位描述中应该还有语言要求,这个刷刷八股,要是对自己语言能力很有把握,那就不用看这点了 4.找下你简历中项目部分,看有没有和岗位描述中技术点重合的,这种在面试提到项目时,是高概率问题 好好准备,祝你面试顺利
我的求职进度条
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务