zoukankan      html  css  js  c++  java
  • 火车运输(最大生成树+lca) 洛谷P1967

    货车运输

    题目描述

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

    输入格式

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

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

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

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

    输出格式

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

    输入输出样例

    输入

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

    输出

    3
    -1
    3
    

    说明/提示

    对于 (30%) 的数据, (1≤n<1000,1≤m<10000,1≤q<1000)
    对于 (60%) 的数据, (1≤n<1000,1≤m<5×10^4,1≤q<1000)
    对于 (100%) 的数据, (1≤n<10^4,1≤m<5×10^4,1≤q<3×10^4,0≤z≤10^5)

    思路

    这道题思路并不难想,最大生成树加上lca,首先把跑一遍kruskal,建一个最大生成树,然后再用lca求最近公共祖先,再搜一遍很简单就可以求出来最小的承重,直接上代码吧。

    代码实现

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N=1e4+10;
    
    struct Edge{//前向星
        int to,nxt,val,fro;
        bool operator <(const Edge &A)const{
            return val>A.val;
        }
    }E[10*N],e[10*N];
    
    int h[N],idx;
    
    void Ins(int a,int b,int c){//建边
        e[++idx].to = b; e[idx].nxt = h[a];h[a] = idx;e[idx].val = c;
    }
    
    int n,m;
    int f[N];
    
    int find(int x){//求祖先
        return f[x] == x ? x: (f[x] = find(f[x]));
    }
    
    void Kruskal(){//建最大生成树
        sort(E+1, E+m+1);
        for(int i = 1; i <= n; i++)
            f[i] = i;
        for(int i = 1; i <= m; i++){
            int u = E[i].fro,v = E[i].to,w = E[i].val;
            if(find(u) != find(v)){
                f[find(u)] = find(v);Ins(u,v,w);Ins(v,u,w);
            }
        }
    }
    
    int p[N][30],dep[N],Min[N][30];
    
    void dfs(int x){//搜索
        for(int i = 0; p[x][i]; i++){
            p[x][i+1] = p[p[x][i]][i];
            Min[x][i+1] = min(Min[x][i],Min[p[x][i]][i]);
        }
        for(int i = h[x]; i; i = e[i].nxt){
            int v = e[i].to;
            if(v == p[x][0]) continue;
            dep[v] = dep[x]+1;
            p[v][0] = x;
            Min[v][0] = e[i].val;
            dfs(v);
        }
    }
    
    int lca(int x,int y){//求最近公共祖先
        if(find(x) != find(y)) return -1;
        if(dep[x] < dep[y]) swap(x,y);
        int d = dep[x] - dep[y];
        int res = 0x7f7f7f7f;
        for(int i = 0; d; i++ , d >>= 1){
            if(d & 1){
                res = min(res, Min[x][i]);
                x = p[x][i];
            }
        }
        if(x == y) return res;
        for(int i = 24; i >= 0; i--){
            if(p[x][i] != p[y][i]){
                res = min(res, min(Min[x][i], Min[y][i]));
                x = p[x][i];y = p[y][i];
            }
        }
        res = min(res, min( Min[x][0], Min[y][0] ) );
        return res;
    }
    
    int main(){
        memset(Min, 0x7f, sizeof(Min));
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= m; i++)
            scanf("%d%d%d", &E[i].fro, &E[i].to, &E[i].val);
        Kruskal();
        int q;
        scanf("%d", &q);
        for(int i = 1; i <= n; i++)
            if(! dep[i]) dfs(i);
        while(q--){
            int a,b;
            scanf("%d%d", &a, &b);
            printf("%d
    ", lca(a,b));
        }
    }
    

    代码并不是很难写,并不过多解释了。

  • 相关阅读:
    02_java基础学习_基础语法(上)01_day02总结
    EditPlus如何设置保存时不产生.bak备份文件?
    UltraEdit(UE)如何设置去掉.bak备份文件?
    如何在win10上连接苹果无线键盘
    01_java基础学习_Java概述_day01总结
    Python 提取Twitter tweets中的元素(包括text, screen names, hashtags)
    #leetcode#Path Sum II
    怎样实现广度优先遍历(BFS)
    GCD编程-串行队列与并发队列
    在对方电脑建立IPC连接, 利用IPC$入侵 运行木马
  • 原文地址:https://www.cnblogs.com/hzoi-liujiahui/p/13205133.html
Copyright © 2011-2022 走看看