zoukankan      html  css  js  c++  java
  • POJ1679 The Unique MST 题解 次小生成树 题解 Kruskal+暴力LCA解法(因为倍增不会写)

    题目链接:http://poj.org/problem?id=1679

    题目大意:
    给你一个简单连通图,判断他的最小生成树是否唯一。

    解题思路:

    首先(我这里用Kruskal算法)求出它的最小生成树(以下简称MST)以及对应的边,然后构造出这棵MST。

    然后我们枚举图上每一条不在此MST上的边,假设这条边的两个端点是 (u)(v),边权为 (w) ,求MST上 (u)(v) 的树链上的最大边的值是否等于 (w),如果等于 (w) 就说明 MST 不唯一。

    这一部分可以用树上倍增算法解决,但是我暂时还不会写,所以我就暴力做了囧。

    所以我这样写的时间复杂度是:

    Kruskal算法的 (O(m log m)) + 枚举每一条边+LCA的 (O(mn)) = (O(m log m + mn))

    实现代码如下:

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <vector>
    using namespace std;
    const int maxn = 110, maxm = 10010;
    int T, n, m, f[maxn], p[maxn], pe[maxn], ans, dep[maxn];
    struct Edge {
        int u, v, w;
        bool choose;
        Edge () { choose = false; };
        Edge (int _u, int _v, int _w) { u = _u; v = _v; w = _w; choose = false; }
    } edge[maxm];
    vector<Edge> g[maxn];
    void init() {
        ans = 0;
        for (int i = 1; i <= n; i ++) {
            g[i].clear();
            f[i] = i;
        }
    }
    int func_find(int x) {
        if (x == f[x]) return x;
        return f[x] = func_find(f[x]);
    }
    void func_union(int x, int y) {
        int a = func_find(x), b = func_find(y);
        f[a] = f[b] = f[x] = f[y] = min(a, b);
    }
    inline bool cmp(Edge a, Edge b) {
        return a.w < b.w;
    }
    void kruskal() {
        int cnt = 0;
        sort(edge, edge+m, cmp);
        for (int i = 0; i < m; i ++) {
            int u = edge[i].u, v = edge[i].v, w = edge[i].w;
            if (func_find(u) != func_find(v)) {
                edge[i].choose = true;
                func_union(u, v);
                ans += w;
                g[u].push_back(Edge(u, v, w));
                g[v].push_back(Edge(v, u, w));
                cnt ++;
                if (cnt >= n-1) break;
            }
        }
    }
    void dfs(int u, int d) {
        dep[u] = d;
        int sz = g[u].size();
        for (int i = 0; i < sz; i ++) {
            int v = g[u][i].v, w = g[u][i].w;
            if (v == p[u]) continue;
            p[v] = u;
            pe[v] = w;
            dfs(v, d+1);
        }
    }
    int find_chain(int u, int v) {
        int maxw = 0;
        while (u != v) {
            if (dep[u] > dep[v]) {
                maxw = max(maxw, pe[u]);
                u = p[u];
            }
            else {
                maxw = max(maxw, pe[v]);
                v = p[v];
            }
        }
        return maxw;
    }
    int main() {
        scanf("%d", &T);
        while (T --) {
            scanf("%d%d", &n, &m);
            init();
            for (int i = 0; i < m; i ++)
                scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].w);
            kruskal();
            dep[1] = 1;
            dfs(1, 1);
            bool is_unique = true;
            for (int i = 0; i < m; i ++) {
                if (!edge[i].choose) {
                    int u = edge[i].u, v = edge[i].v, w = edge[i].w;
                    if (find_chain(u, v) == w) {
                        is_unique = false;
                        break;
                    }
                }
            }
            if (is_unique) printf("%d
    ", ans);
            else puts("Not Unique!");
        }
        return 0;
    }
    
  • 相关阅读:
    滚动页面时DIV到达顶部时固定在顶部
    【Java学习笔记】拾遗
    【Java学习笔记】文件信息
    【Java学习笔记】使用BufferedReader类(流的读写)
    【Java学习笔记】可变参数
    【Java学习笔记】控制台读写
    【Java学习笔记】关于默认值
    【Java学习笔记】FileChannel的学习
    【JAVA学习笔记】静态导入
    【Java学习笔记】Java中关于tostring方法的误操作
  • 原文地址:https://www.cnblogs.com/quanjun/p/12253091.html
Copyright © 2011-2022 走看看