zoukankan      html  css  js  c++  java
  • [洛谷P1967] 货车运输

    Description

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

    Input

    第一行有两个用一个空格隔开的整数 (n,m),表示 (A) 国有 (n) 座城市和 (m) 条道路。

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

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

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

    Output

    共有 (q) 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。如果货车不能到达目的地,输出 (-1)

    Sample Input

    4 3
    1 2 4
    2 3 3
    3 1 1
    3
    1 3
    1 4
    1 3

    Sample Output

    3
    -1
    3

    HINT

    对于 (30%) 的数据,(0 < n < 1,000,0 < m < 10,000,0 < q< 1,0000<n<1,000,0<m<10,000,0<q<1,000)

    对于 (60%) 的数据, (0 < n < 1,000,0 < m < 50,000,0 < q< 1,0000<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,0000<n<10,000,0<m<50,000,0<q<30,000,0≤z≤100,000)


    题解

    也是一道比较经典最小瓶颈树题目。

    $Kruskal + lca倍增 $
    贪心想法,边权由小向大加,用并查集维护连通性。然后一想发现这就是 (Kruskal)
    感觉这题跟今年 (NOI d1t1) 有些像啊,那道说是什么 (Kruskal重构树) ……

    顺便提一个结论:
    其实最小生成树就是最小瓶颈树,这是可以证明滴~(想想 (Kruskal) 的贪心过程就可以明白)


    代码

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    
    using namespace std;
    
    const int N = 10005;
    
    struct node{
        int v,len;
        node *next;
    }pool[N*2],*h[N];
    int cnt;
    void addedge(int u,int v,int len){
        node *p=&pool[++cnt],*q=&pool[++cnt];
        p->v=v;p->next=h[u];h[u]=p;p->len=len;
        q->v=u;q->next=h[v];h[v]=q;q->len=len;
    }
    
    int n,m;
    int f[N][15],fmin[N][15],dep[N];
    void dfs(int u){
        int v;
        for(node *p=h[u];p;p=p->next)
            if(!dep[v=p->v]){
                dep[v]=dep[u]+1;
                f[v][0]=u; fmin[v][0]=p->len;
                for(int j=1;j<15;j++){
                    f[v][j]=f[f[v][j-1]][j-1];
                    fmin[v][j]=min(fmin[v][j-1],fmin[f[v][j-1]][j-1]);
                }
                dfs(v);
            }
    }
    int query(int x,int y){
        int ret=100005;
        if(dep[x]<dep[y]) swap(x,y);
        for(int i=14;i>=0;i--)
            if(dep[f[x][i]]>=dep[y]) ret=min(ret,fmin[x][i]),x=f[x][i];
        if(x==y) return ret;
        for(int i=14;i>=0;i--)
            if(f[x][i]!=f[y][i]){
                ret=min(ret,min(fmin[x][i],fmin[y][i]));
                x=f[x][i]; y=f[y][i];
            }
        ret=min(ret,min(fmin[x][0],fmin[y][0]));
        return ret;
    }
    
    struct edge{
        int x,y,z;
        bool operator < (const edge &b) const { return z>b.z; }
    }ed[N*5];
    int fa[N];
    int getfa(int x) { return fa[x]==x ? x : fa[x]=getfa(fa[x]) ; }
    void merge(int x,int y){
        x=getfa(x); y=getfa(y);
        fa[x]=y;
    }
    
    int main()
    {
        int x,y,q;
        scanf("%d%d",&n,&m);
        for(int i=0;i<m;i++) scanf("%d%d%d",&ed[i].x,&ed[i].y,&ed[i].z);
        
        sort(ed,ed+m);
        for(int i=1;i<=n;i++) fa[i]=i;
        for(int i=0;i<m;i++){
            if(getfa(ed[i].x)==getfa(ed[i].y)) continue;
            addedge(ed[i].x,ed[i].y,ed[i].z);
            merge(ed[i].x,ed[i].y);
        }
        
        for(int j=0;j<15;j++) fmin[0][j]=100005;
        for(int i=1;i<=n;i++){
            if(dep[i]) continue;
            for(int j=0;j<15;j++) fmin[i][j]=100005;
            dep[i]=1;
            dfs(i);
        }
        
        scanf("%d",&q);
        while(q--){
            scanf("%d%d",&x,&y);
            if(getfa(x)!=getfa(y)) printf("-1
    ");
            else printf("%d
    ",query(x,y));
        }
        
        return 0;
    }
    
    既然选择了远方,便只顾风雨兼程
  • 相关阅读:
    09-排序1 排序
    06-图3 六度空间
    06-图2 Saving James Bond
    06-图1 List Components
    04-树5 Complete Binary Search Tree
    03-树2 Tree Traversals Again
    PAT 05-树8 Huffman Codes
    Egret引擎的visible两次开关闭问题
    Egret的项目笔记(一)
    Egret屏幕适配【转】
  • 原文地址:https://www.cnblogs.com/lindalee/p/9733447.html
Copyright © 2011-2022 走看看