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

    题目描述

    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。

    /*
    因为要求的是每个司机的载重限制的最大值,所以建一棵最大生成树,也用kruskal来做,但是边权从大到小排序,
    生成的最大树上两点间的最小边权就是最大载重。 
    不用加两条边,加一条边就可以。
    生成了树之后,处理处每个点的lca,以便求最大载重。
    
    怎么求lca?
    在跑Kruskal将两个树合并的时候,在两棵树根节点之间连一条边,把连的边保存下来 
    让b树的根的爸爸指向a树的根 ——> 
    Add_edge(father[fx],fy,edge1[i].w);
    father[fy]=fx;
    如果一个点的father等于他本身,那么这就是一个树根。然后从这个dfs求lca,因为可能有多棵树,所以for循环枚举一遍。 
    
    怎样判断能不能到达? 
    如果两个点所属的连通块不同——>find(x)!=find(y),则无法到达。 
    
    那么怎么求最大载重呢?
    在dfs求lca时候,记录下每个点到他的父亲节点的距离,进行一次询问的时候,求出两个点的lca,然后一直沿着父亲节点跳,知道跳到lca为止,跳的时候取min 
    
    */
    
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define N 10005
    using namespace std;
    
    int n,m,num_edge1,num_edge,q,x,y,z;
    int head1[N],head[N],father[N],deep[N];
    int fa[N][16],dis[N],chudu[N];
    struct Edge
    {
        int u,v,w,next;
        bool operator < (Edge a) const
        {
            return w>a.w;
        }
    }edge1[N*5],edge[N];
    
    void read(int &num)
    {
        num=0;
        char c=getchar();
        for(;!isdigit(c);c=getchar());
        for(;isdigit(c);c=getchar()){num=num*10+c-'0';}
    }
    
    void add_edge(int u,int v,int w)
    {
        edge1[++num_edge1].u=u;
        edge1[num_edge1].v=v;
        edge1[num_edge1].w=w;
        edge1[num_edge1].next=head1[u];
        head1[u]=num_edge1;
    }
    
    void Add_edge(int u,int v,int w)
    {
        edge[++num_edge].u=u;
        edge[num_edge].v=v;
        edge[num_edge].w=w;
        edge[num_edge].next=head[u];
        head[u]=num_edge;
    }
    
    int find(int x)
    {
        if(father[x]!=x) father[x]=find(father[x]);
        return father[x];
    }
    
    void Kruskal()
    {
        for(int i=1;i<=n;i++) father[i]=i;
        sort(edge1+1,edge1+m+1);
        for(int i=1;i<=m;i++)
        {
            int fx=find(edge1[i].u),fy=find(edge1[i].v);
            if(fx==fy) continue;
            Add_edge(father[fx],fy,edge1[i].w);        //生成的树,保存下来,用来dfs处理lca 
            father[fy]=fx;
        }
    }
    
    void dfs(int u)        //处理lca 
    {
        for(int i=1;i<=14;i++)
        {
            fa[u][i]=fa[fa[u][i-1]][i-1];
        }
        for(int i=head[u];i;i=edge[i].next)
        {
            if(fa[u][0]==edge[i].v) continue;
            fa[edge[i].v][0]=u;
            dis[edge[i].v]=edge[i].w;        //到父亲节点的距离 
            deep[edge[i].v]=deep[u]+1;
            dfs(edge[i].v);
        }
    }
    
    int get_lca(int x,int y)    //求lca 
    {
        if(deep[x]<deep[y]) swap(x,y);
        int h=deep[x]-deep[y];
        for(int i=14;i>=0;i--)
        {
            if(h&(1<<i))
                x=fa[x][i];
        }
        if(x!=y)
        {
            for(int i=14;i>=0;i--)
            {
                if(fa[x][i]!=fa[y][i])
                {
                    x=fa[x][i];
                    y=fa[y][i];
                }
            }
            x=fa[x][0];
        }
        return x;
    }
    
    int work(int x,int y)        //求最大载重 
    {
        int a=999999999,b=999999999;
        int lca=get_lca(x,y);
        //printf("lca:  %d
    ",lca);
        for(int i=x;i!=lca;i=fa[i][0])        //a往lca跳 
        {
            a=min(a,dis[i]);
        }
        for(int i=y;i!=lca;i=fa[i][0])        //b往lca跳 
        {
            b=min(b,dis[i]);
        }
        return min(a,b);
    }
    
    int main()
    {
        read(n),read(m);
        for(int i=1;i<=m;i++)
        {
            read(x),read(y),read(z);
            add_edge(x,y,z);
            //printf("z:  %d
    ",z);
            //printf("W:  %d
    ",edge1[i].w);
        }
        Kruskal();
        for(int i=1;i<=n;i++)
        {
            if(find(i)==i)    //本来写的father[i]=i,严谨点其实应该是find(i)=i,数据问题吧 
            {
                fa[i][0]=i;
                //printf("root:  %d
    ",i);
                dfs(i);
            }
        }
        read(q);
        /*for(int i=1;i<=n;i++)
        {
            //printf("hh:  %d %d
    ",fa[i][0],dis[i]);
        }*/
        for(int i=1;i<=q;i++)
        {
            read(x),read(y);
            if(find(x)!=find(y))
            {
                printf("-1
    ");
                continue;
            }
            printf("%d
    ",work(x,y));
        }
        fclose(stdin);
        fclose(stdout);
        return 0;
    }
  • 相关阅读:
    Python3学习笔记(十二):闭包
    Python3学习笔记(十一):函数参数详解
    PostgreSQL psql中如何查看快捷功能的对应函数
    PostgreSQL逻辑复制槽 pg_recvlogical test_decoding wal2json
    记一次内存占用过高的分析
    数据库一致性解读
    PostgreSQL常用插件收集
    PostgreSQL truncate table会释放索引的空间
    PostgreSQL锁级别及什么操作获取什么锁
    PostgreSQL设置事务隔离级别实验
  • 原文地址:https://www.cnblogs.com/lovewhy/p/8717763.html
Copyright © 2011-2022 走看看