zoukankan      html  css  js  c++  java
  • 【CODEVS 3287】【NOIP2013】火车运输

    http://codevs.cn/problem/3287/

    题目描述

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

    输入格式

    输入文件第一行有两个用一个空格隔开的整数 n,m, 表示 A 国有 n 座城市和 m 条道
    路。
    接下来 m 行每行 3 个整数 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

    数据范围

    0$	extless$n$	extless$10000,0$	extless$m$	extless$50000,0$	extless$q$	extless$30000,0$leq$z$leq$100000

    题解

    可以证明最优路径一定在最大生成树(森林)上,于是题目便转化为,询问森林中两点路径上边权最小值,连通性用并查集判断即可。

    对于一棵树上的一次询问,可以用倍增的方法解决。

    anc[i][j] 表示点 i 向上 2^j 步到达的结点                            anc[i][j]=anc[anc[i][j-1]][j-1]

    g[i][j] 表示点 i 向上 2^j 步的路径中的边权最小值 g[i][j]=min(g[i][j-1],g[anc[i][j-1]][j-1])

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #include<stack>
    #define N 10005
    #define M 50005
    #define depth 21
    using namespace std;
    
    int n,m,q,cnt,tot,ans;
    int f[N],last[N],dep[N];
    int anc[N][22],g[N][22];
    struct hh
    {int to,next,w;}e[M<<1];
    struct hhh
    {int l,r,w;}line[M<<1];
    bool cmp(hhh a,hhh b){return a.w>b.w;}
    int read()
    {
        int ret=0;char c=getchar();
        while(!isdigit(c))c=getchar();
        while(isdigit(c)){ret=(ret<<1)+(ret<<3)+c-'0';c=getchar();}
        return ret;
    }
    void add(int a,int b,int w)
    {
        e[++tot].to=b;
        e[tot].next=last[a];
        e[tot].w=w;
        last[a]=tot;
    }
    void bfs(int root)
    {
        int i,j,now;
        stack<int> s;
        s.push(root);dep[root]=1;
        for(i=0;i<depth;i++) anc[root][i]=root;
        while(!s.empty())
        {
            now=s.top();s.pop();    
            if(now!=root)
                for(i=1;i<depth;i++)
                {
                    anc[now][i]=anc[anc[now][i-1]][i-1];
                    g[now][i]=min(g[now][i-1],g[anc[now][i-1]][i-1]);
                }                
            for(i=last[now];i;i=e[i].next)
                if(!dep[e[i].to])
                {
                    anc[e[i].to][0]=now;
                    dep[e[i].to]=dep[now]+1;
                    g[e[i].to][0]=e[i].w;
                    s.push(e[i].to);
                }
        }
    }
    void swim(int& x,int h)
    {
        int i;
        for(i=0;h;i++)
        {
            if(h&1) x=anc[x][i];
            h>>=1;
        }
    }
    int getlca(int x,int y)
    {
        int i,j;
        if(dep[x]<dep[y]) swap(x,y);
        swim(x,dep[x]-dep[y]);
        if(x==y) return x;
        while(true)
        {
            for(i=0;anc[x][i]!=anc[y][i];i++);
            if(!i) return anc[x][0];
            x=anc[x][i-1];y=anc[y][i-1];
        }
    }
    int query(int x,int y)
    {
        int i,ret=9999999,h;
        h=dep[y]-dep[x];
        for(i=depth;i>=0;i--)
            if((1<<i)<=h)
            {
                h-=(1<<i);
                ret=min(ret,g[y][i]);
                y=anc[y][i];
            }
        return ret;
    }
    int find(int x){return f[x]==x?x:f[x]=find(f[x]);}
    int main()
    {
        int i,j,u,v,w,fx,fy,lca;
        n=read();m=read();
        for(i=1;i<=m;i++)
            line[i].l=read(),line[i].r=read(),line[i].w=read();
        sort(line+1,line+1+m,cmp);
        for(i=1;i<=n;i++) f[i]=i;
        for(i=1;i<=m;i++)
        {
            u=line[i].l;v=line[i].r;w=line[i].w;
            fx=find(u);fy=find(v);
            if(fx!=fy)
            {
                f[fx]=fy;cnt++;
                add(u,v,w);add(v,u,w);
                if(cnt==n-1) break;
            }
        }
        for(i=1;i<=n;i++)
            for(j=0;j<depth;j++)
                g[i][j]=9999999;
        bfs(1);
        q=read();
        for(i=1;i<=q;i++)
        {
            u=read();v=read();
            if(find(u)!=find(v)){puts("-1");continue;}
            lca=getlca(u,v);
            ans=min(query(lca,u),query(lca,v));
            printf("%d
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    14-6-27&28自学内容小结
    暑假要自学Java了
    找最大值算法(面试题)
    冒泡排序(面试题)
    循环
    运算符和表达式 、 分支结构 使用三目运算符的嵌套,比较a、b、c三个整数的大小并输出结果
    运算符和表达式 、 分支结构 输入年份和月份,输出该月的天数(使用switch-case)
    运算符和表达式 、 分支结构 3 个数值进行升序排列
    运算符和表达式 、 分支结构 例题 闰年判断
    变量 、 JAVA基本类型 3.3.5. 关于“短路逻辑”的问题
  • 原文地址:https://www.cnblogs.com/yljiang/p/6034192.html
Copyright © 2011-2022 走看看