zoukankan      html  css  js  c++  java
  • 洛谷P1967 货车运输 题解 最大生成树+LCA

    题目链接:https://www.luogu.com.cn/problem/P1967

    解题思路:

    1. 先求最大生成树;
    2. 在用LCA求路径最小边。

    示例代码:

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 10010, maxm = 100010;
    int n, m, f[maxn];
    void init() {
        for (int i = 1; i <= n; i ++) f[i] = i;
    }
    int func_find(int x) {
        return x == f[x] ? x : 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);
    }
    struct E {
        int u, v, z;
    } e[maxm];
    bool cmp(E a, E b) {
        return a.z > b.z;
    }
    struct Edge {
        int u, v, z, nxt;
        Edge() {};
        Edge(int _u, int _v, int _z, int _nxt) { u = _u; v = _v; z = _z; nxt = _nxt; }
    } edge[maxm];
    int head[maxn], ecnt;
    void init_e() {
        ecnt = 0;
        memset(head, -1, sizeof(int)*(n+1));
    }
    void addedge(int u, int v, int z) {
        edge[ecnt] = Edge(u, v, z, head[u]); head[u] = ecnt ++;
        edge[ecnt] = Edge(v, u, z, head[v]); head[v] = ecnt ++;
    }
    void kruskal() {
        init();
        init_e();
        sort(e, e+m, cmp);
        int cnt = 0;
        for (int i = 0; i < m; i ++) {
            int u = e[i].u, v = e[i].v;
            if (func_find(u) != func_find(v)) {
                cnt ++;
                func_union(u, v);
                addedge(u, v, e[i].z);
                if (cnt >= n-1) break;
            }
        }
    }
    int pa[maxn][15], zz[maxn][15], dep[maxn];
    void dfs(int u, int p, int z) {
        dep[u] = dep[p] + 1;
        pa[u][0] = p;
        zz[u][0] = z;
        for (int i = 1; (1<<i) <= dep[u]; i ++) {
            pa[u][i] = pa[ pa[u][i-1] ][i-1];
            zz[u][i] = min(zz[u][i-1], zz[ pa[u][i-1] ][i-1]);
        }
        for (int i = head[u]; i != -1; i = edge[i].nxt) {
            int v = edge[i].v;
            if (v == p) continue;
            dfs(v, u, edge[i].z);
        }
    }
    /**
     lca(x,y): 返回x到y路径上最小边权
    */
    int lca(int x, int y) {
        int ans = INT_MAX;
        if (dep[x] < dep[y]) swap(x, y);
        for (int i = 14; i >= 0; i --) {
            if (dep[ pa[x][i] ] >= dep[y]) {
                ans = min(ans, zz[x][i]);
                x = pa[x][i];
            }
            if (x == y) return ans;
        }
        for (int i = 14; i >= 0; i --) {
            if (pa[x][i] != pa[y][i]) {
                ans = min(ans, zz[x][i]);
                x = pa[x][i];
                ans = min(ans, zz[y][i]);
                y = pa[y][i];
            }
        }
        ans = min(ans, zz[x][0]);
        ans = min(ans, zz[y][0]);
        return ans;
    }
    int main() {
        cin >> n >> m;
        for (int i = 0; i < m; i ++) cin >> e[i].u >> e[i].v >> e[i].z;
        kruskal();
        memset(zz, 0x3f, sizeof(zz));
        dfs(1, 0, INT_MAX);
        int q, x, y;
        cin >> q;
        while (q --) {
            cin >> x >> y;
            if (func_find(x) != func_find(y)) cout << -1 << endl;
            else cout << lca(x, y) << endl;
        }
        return 0;
    }
    
  • 相关阅读:
    前端学习(六):body标签(四)
    前端学习(五):body标签(三)
    前端学习(四):body标签(二)
    前端学习(三):body标签(一)
    volatile的作用以及原理解析
    【转载】synchronized锁的升级过程
    从三个层面解析synchronized原理
    将网页图片转base64打包导出实战和踩坑
    synchronized锁住的到底是什么以及用法作用
    多线程之程序的局部性原理和伪共享问题
  • 原文地址:https://www.cnblogs.com/quanjun/p/13812788.html
Copyright © 2011-2022 走看看