zoukankan      html  css  js  c++  java
  • noip2013 货车运输

    P1967 货车运输

      • 406通过
      • 1.4K提交
    • 题目提供者该用户不存在
    • 标签图论贪心2013NOIp提高组
    • 难度提高+/省选-

    提交该题 讨论 题解 记录

    最新讨论

    题目描述

    A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路。每一条道路对车辆都有重量限制,简称限重。现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。

    输入输出格式

    输入格式:

    输入文件名为 truck.in。

    输入文件第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道

    路。 接下来 m 行每行 3 个整数 x、 y、 z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条限重为 z 的道路。意:x 不等于 y,两座城市之间可能有多条道路。

    接下来一行有一个整数 q,表示有 q 辆货车需要运货。

    接下来 q 行,每行两个整数 x、y,之间用一个空格隔开,表示一辆货车需要从 x 城市运输货物到 y 城市,注意:x 不等于 y。

    输出格式:

    输出文件名为 truck.out。

    输出共有 q 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。如果货

    车不能到达目的地,输出-1。

    输入输出样例

    输入样例#1:
    4 3
    1 2 4
    2 3 3
    3 1 1
    3
    1 3
    1 4
    1 3
    输出样例#1:
    3
    -1
    3

    说明

    对于 30%的数据,0 < n < 1,000,0 < m < 10,000,0 < q< 1,000; 对于 60%的数据,0 < n < 1,000,0 < m < 50,000,0 < q< 1,000; 对于 100%的数据,0 < n < 10,000,0 < m < 50,000,0 < q< 30,000,0 ≤ z ≤ 100,000。

    分析:这道题目就是求x到y的路径上最小值最大的权值,固定的方法就是最大生成树,当然如果是最大值最小,那么就是最小生成树.怎么求最大生成树呢?首先要是一棵树,两个点之间只有唯一的路径,怎么判断两个点是否连通呢?并查集!怎么要满足“最大”呢?排序!那么就先从大到小排序,把不在一个连通块的两个点连起来就可以了.那么就要求最小值最大,怎么求呢?可以知道这条唯一的路径是两个点到它们的lca的和,怎么求lca呢?倍增!首先一次dfs记录出f[i][j],g[i][j],即第i个节点的第2^j个祖先和所求的最小值最大的结果.同时记录下每个节点的深度,注意,这个深度是越大越往下.为了求lca(a,b),假设a的深度比b的深度大,那么把a往上移,直到深度相同,同时更新ans,这个时候如果a==b了,那么就返回,然后再让两个点同时上移,如果两个点上移之后相等了,因为我们是从大到小枚举2^j的,所以求出的点可能在lca上面,所以当两个祖先不是相同的才跳.那么跳到最后就跳到了lca的下一层,往上再跳一个就可以了.每次跳都要更新ans.

    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int maxn = 10010, maxm = 50010;
    
    int n, m, q, fa[maxn], head[maxn], cnt, h[maxn], f[maxn][20], g[maxn][20], ans = 1000000000;
    bool vis[maxn];
    
    struct node
    {
        int x, y, z;
    }a[maxm];
    
    struct node2
    {
        int nextt, to, w;
    }e[maxn * 2];
    
    bool cmp(node a1, node b)
    {
        return a1.z > b.z;
    }
    
    void dfs(int u, int depth)
    {
        vis[u] = true;
        h[u] = depth;
        for (int i = head[u]; i; i = e[i].nextt)
            if (!vis[e[i].to])
            {
            f[e[i].to][0] = u;
            g[e[i].to][0] = e[i].w;
            dfs(e[i].to, depth + 1);
            }
        return;
    }
    
    int find(int x)
    {
        if (fa[x] != x)
            fa[x] = find(fa[x]);
        return fa[x];
    }
    
    void add(int p, int q, int v)
    {
        e[++cnt].to = q;
        e[cnt].nextt = head[p];
        head[p] = cnt;
        e[cnt].w = v;
    }
    
    void kruskal()
    {
        sort(a + 1, a + 1 + m, cmp);
        for (int i = 1; i <= n; i++)
            fa[i] = i;
        for (int i = 1; i <= m; i++)
        {
            int fx = find(a[i].x), fy = find(a[i].y);
            if (fx == fy)
                continue;
            fa[fx] = fy;
            add(a[i].x, a[i].y, a[i].z);
            add(a[i].y, a[i].x, a[i].z);
        }
    }
    
    int lca(int a1, int b1)
    {
        ans = 1000000000;
        if (a1 == b1)
            return 0;
        if (h[a1] < h[b1])
            swap(a1, b1);
        int k = int(log2(h[a1]));
        for (int i = k; i >= 0; i--)
            if (h[a1] - (1 << i) >= h[b1])
            {
            ans = min(ans, g[a1][i]);
            a1 = f[a1][i];
            }
        if (a1 == b1)
            return ans;
        for (int i = k; i >= 0; i--)
            if (f[a1][i] && f[a1][i] != f[b1][i])
            {
            ans = min(ans, min(g[a1][i], g[b1][i]));
            a1 = f[a1][i];
            b1 = f[b1][i];
            }
        ans = min(ans, min(g[a1][0], g[b1][0]));
        return ans;
    }
    
    int main()
    {
        memset(vis, false, sizeof(vis));
        memset(head, 0, sizeof(head));
        memset(f, 0, sizeof(f));
        memset(g, 127, sizeof(g)); //INF
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= m; i++)
            scanf("%d%d%d", &a[i].x, &a[i].y, &a[i].z);
        kruskal();
        scanf("%d", &q);
        for (int i = 1; i <= n; i++)
            if (!vis[i])
            dfs(i, 1);
        for (int j = 1; (1 << j) <= n; j++)
            for (int i = 1; i <= n; i++)
                if (f[i][j - 1])
                {
            f[i][j] = f[f[i][j - 1]][j - 1];
            g[i][j] = min(g[i][j - 1], g[f[i][j - 1]][j - 1]);
                }
        for (int i = 1; i <= q; i++)
        {
            int x, y;
            scanf("%d%d", &x, &y);
            if (find(x) != find(y))
                printf("-1
    ");
            else
                printf("%d
    ", lca(x, y));
        }
    
        return 0;
    }
  • 相关阅读:
    Linux内存地址映射
    江湖行
    数组/指针/const/字符串常量的使用传值问题
    TI davinci DM6467通过串口0将UBL和u-boot写入NAND flash
    CCS5配置使用GenCodecPkg生成CODEC SERVER
    typedef用法和与define的区别
    VS2008项目移植到Linux
    bootargs中ip段各项解释
    Davinci-DM6467板子-外围器件的I2C地址的疑惑解答
    MFC中界面自适应
  • 原文地址:https://www.cnblogs.com/zbtrs/p/5744914.html
Copyright © 2011-2022 走看看