• 【NOIP2013提高组】货车运输


    https://www.luogu.org/problem/show?pid=1967

    思考一下,将图的所有边按边权从大到小依次加入图,则当u与v第一次连通时,刚加入的边就是使u与v两点的路径中的最小边最大的边。

    将图的所有边按边权从大到小依次加入图?这不就是Kruscal算法最大生成树吗!

    所以我们只需要对原图求最大生成树,对于每个询问求两点的路径上的最小边就可以了。虽然可以用树剖+ST表优化,但是暴力求LCA+暴力爬链也能过了。

    暴力LCA+暴力爬链:

    #include <algorithm>
    #include <cmath>
    #include <iostream>
    #include <vector>
    #define maxn 10005
    #define maxq 30005
    using namespace std;
    int n, m;
    
    //
    struct edge
    {
        int from, to, weight;
    };
    bool cmp(const edge& x, const edge& y)
    {
        return x.weight > y.weight;
    }
    vector<edge> edges;
    vector<int> tree[maxn];
    void addedge(int u, int v, int w)
    {
        edges.push_back((edge){u, v, w});
        tree[u].push_back(edges.size() - 1);
        edges.push_back((edge){v, u, w});
        tree[v].push_back(edges.size() - 1);
    }
    bool visited[maxn];
    int depth[maxn], parent[maxn];
    int weight[maxn];
    void buildtree(int v, int fr, int d)
    {
        depth[v] = d;
        parent[v] = fr;
        visited[v] = true;
        for (int i = 0; i < tree[v].size(); i++)
        {
            int w = edges[tree[v][i]].to;
            if (w != fr)
            {
                weight[w] = edges[tree[v][i]].weight;
                buildtree(w, v, d + 1);
            }
        }
    }
    int lca(int x, int y)
    {
        while (x != y)
        {
            if (depth[x] < depth[y])
                swap(x, y);
            x = parent[x];
        }
        return x;
    }
    int minedge(int v, int w)
    {
        int x = lca(v, w), ans = 0x7fffffff;
        while (v != x)
        {
            ans = min(ans, weight[v]);
            v = parent[v];
        }
        while (w != x)
        {
            ans = min(ans, weight[w]);
            w = parent[w];
        }
        return ans;
    }
    
    // 并查集与Kruscal
    namespace djs
    {
    int parent[maxn];
    void init()
    {
        for (int i = 1; i <= n; i++)
            parent[i] = -1;
    }
    int find(int x)
    {
        if (parent[x] < 0)
            return x;
        else
            return parent[x] = find(parent[x]);
    }
    void merge(int x, int y)
    {
        x = find(x);
        y = find(y);
        if (x == y)
            return;
        if (parent[x] > parent[y])
            swap(x, y);
        parent[x] += parent[y];
        parent[y] = x;
    }
    bool related(int x, int y)
    {
        return find(x) == find(y);
    }
    }
    vector<edge> e;
    void kruscal()
    {
        sort(e.begin(), e.end(), cmp);
        djs::init();
    
        int cnt = 0;
        for (int i = 0; i < e.size(); i++)
        {
            if (!djs::related(e[i].from, e[i].to))
            {
                djs::merge(e[i].from, e[i].to);
                addedge(e[i].from, e[i].to, e[i].weight);
                cnt++;
            }
        }
    }
    
    int main()
    {
        ios::sync_with_stdio(false);
        cin >> n >> m;
        int a, b, c;
        for (int i = 1; i <= m; i++)
        {
            cin >> a >> b >> c;
            e.push_back((edge){a, b, c});
        }
        kruscal();
        for (int i = 1; i <= n; i++)
        {
            if (!visited[i])
                buildtree(i, 0, 1);
        }
    
        int nq;
        cin >> nq;
        for (int i = 1; i <= nq; i++)
        {
            cin >> a >> b;
            if (djs::related(a, b))
                cout << minedge(a, b) << endl;
            else
                cout << -1 << endl;
        }
        return 0;
    }

    树剖+ST表优化:

    #include <algorithm>
    #include <cmath>
    #include <iostream>
    #include <vector>
    #define maxn 10005
    #define maxq 30005
    using namespace std;
    const int inf = 0x7fffffff;
    int n, m;
    // ST表
    namespace st
    {
    int logn[maxn];
    int dp[maxn][15];
    int val[maxn];
    void init()
    {
        for (int i = 1; i <= n; i++)
        {
            dp[i][0] = val[i];
            logn[i] = log(i) / log(2);
        }
    
        // f(i,j)=min{f(i,j-1),f(i+2^(j-1),j-1)}
        int limit = logn[n] + 1;
        for (int j = 1; j <= limit; j++)
        {
            for (int i = 1; i <= n; i++)
            {
                if (i + (1 << (j - 1)) <= n)
                    dp[i][j] = min(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1]);
                else
                    dp[i][j] = dp[i][j - 1];
            }
        }
    }
    int min(int l, int r)
    {
        if (l > r)
            return 0x7fffffff;
        // return max{f(l,k),f(r-2^k+1,k)}
        int k = logn[r - l + 1];
        return std::min(dp[l][k], dp[r - (1 << k) + 1][k]);
    }
    }
    
    // 树与树剖
    struct edge
    {
        int from, to, weight;
    };
    bool cmp(const edge &x, const edge &y)
    {
        return x.weight > y.weight;
    }
    vector<edge> edges;
    vector<int> tree[maxn];
    void addedge(int u, int v, int w)
    {
        edges.push_back((edge){u, v, w});
        tree[u].push_back(edges.size() - 1);
        edges.push_back((edge){v, u, w});
        tree[v].push_back(edges.size() - 1);
    }
    bool visited[maxn];
    int size[maxn], depth[maxn], parent[maxn], heavy[maxn];
    int weight[maxn];
    void buildtree(int v, int fr, int d)
    {
        depth[v] = d;
        parent[v] = fr;
        size[v] = 1;
        heavy[v] = 0;
        visited[v] = true;
        for (int i = 0; i < tree[v].size(); i++)
        {
            int w = edges[tree[v][i]].to;
            if (w != fr)
            {
                weight[w] = edges[tree[v][i]].weight;
                buildtree(w, v, d + 1);
                size[v] += size[w];
                if (size[heavy[v]] < size[w])
                    heavy[v] = w;
            }
        }
    }
    int timer = 1;
    int top[maxn], hashh[maxn];
    void slpf(int v, int tp)
    {
        st::val[timer] = weight[v];
        hashh[v] = timer++;
        top[v] = tp;
        if (heavy[v])
        {
            slpf(heavy[v], tp);
            for (int i = 0; i < tree[v].size(); i++)
            {
                int w = edges[tree[v][i]].to;
                if (w != parent[v] && w != heavy[v])
                    slpf(w, w);
            }
        }
    }
    int minedge(int v, int w)
    {
        int ans = 0x7fffffff;
        int vp, wp;
        while (true)
        {
            vp = top[v];
            wp = top[w];
            if (vp == wp)
                break;
            if (depth[vp] < depth[wp])
            {
                swap(v, w);
                swap(vp, wp);
            }
            ans = min(ans, st::min(hashh[vp], hashh[v]));
            v = parent[vp];
        }
        if (depth[v] > depth[w])
            swap(v, w);
        ans = min(ans, st::min(hashh[v] + 1, hashh[w]));
        return ans;
    }
    
    // 并查集与Kruscal
    namespace djs
    {
    int parent[maxn];
    void init()
    {
        for (int i = 1; i <= n; i++)
            parent[i] = -1;
    }
    int find(int x)
    {
        if (parent[x] < 0)
            return x;
        else
            return parent[x] = find(parent[x]);
    }
    void merge(int x, int y)
    {
        x = find(x);
        y = find(y);
        if (x == y)
            return;
        if (parent[x] > parent[y])
            swap(x, y);
        parent[x] += parent[y];
        parent[y] = x;
    }
    bool related(int x, int y)
    {
        return find(x) == find(y);
    }
    }
    vector<edge> e;
    void kruscal()
    {
        sort(e.begin(), e.end(), cmp);
        djs::init();
    
        int cnt = 0;
        for (int i = 0; i < e.size(); i++)
        {
            if (!djs::related(e[i].from, e[i].to))
            {
                djs::merge(e[i].from, e[i].to);
                addedge(e[i].from, e[i].to, e[i].weight);
                cnt++;
            }
        }
    }
    
    int main()
    {
        ios::sync_with_stdio(false);
        cin >> n >> m;
        int a, b, c;
        for (int i = 1; i <= m; i++)
        {
            cin >> a >> b >> c;
            e.push_back((edge){a, b, c});
        }
        kruscal();
        for (int i = 1; i <= n; i++)
        {
            if (!visited[i])
            {
                buildtree(i, 0, 1);
                slpf(i, i);
            }
        }
        st::init();
    
        int nq;
        cin >> nq;
        for (int i = 1; i <= nq; i++)
        {
            cin >> a >> b;
            if (djs::related(a, b))
                cout << minedge(a, b) << endl;
            else
                cout << -1 << endl;
        }
        return 0;
    }
  • 相关阅读:
    理解极大似然估计(MLE)
    模型评估——ROC、KS
    tf.estimator.Estimator类的用法
    TensorFlow中数据读取之tfrecords
    常用数据库的启动与关闭
    几种常见的损失函数
    目标检测模型的性能评估--MAP(Mean Average Precision)
    正则化如何防止过拟合
    Android学习笔记之ConnectivityManager+NetWorkInfo
    关于2015年的相关总结
  • 原文地址:https://www.cnblogs.com/ssttkkl/p/7531863.html
Copyright © 2020-2023  润新知