• 货车运输


    【题目描述】

    A国有n座城市,编号从1~n,这些城市之间有m条双向道路,每一条道路对车辆都有限重。

    现有q辆货车在运输货物,询问在不超过车辆限重的情况下,每辆车最多能运输多重的货物。

    【输入描述】

    第一行输入两个整数n、m,表示A国有n座城市和m条道路;

    接下来m行,每行输入三个整数x、y、z,表示从x号城市到y号城市存在一条限重为z的道路;

    接下来一行输入一个整数q,表示有q辆货车需要运输货物;

    接下来q行,每行输入两个整数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%的数据,0 < n < 1000,0 < m < 10000,0 < q < 1000; 

    对于60%的数据,0 < n < 1000,0 < m < 50000,0 < q < 1000; 

    对于100%的数据,0 < n < 10000,0 < m < 50000,0 < q < 30000,0 ≤ z ≤ 100000。

    源代码:
    
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    struct Node1
    {
        int X,Y,S;
    }Map[50001];
    struct Node2
    {
        int S,To,Next;
    }Edge[20001];
    int m,n,Sum,Num(0),Number(0),F[10001],Head[10001],Deep[10001],f[10001][17],i[10001][17];
    void Add(int t1,int t2,int t) //边表。
    {
        Edge[++Num].S=t;
        Edge[Num].To=t2;
        Edge[Num].Next=Head[t1];
        Head[t1]=Num;
    }
    int Find(int t) //并查集。
    {
        if (!F[t])
          return t;
        return F[t]=Find(F[t]);
    }
    bool Rule(Node1 t1,Node1 t2)
    {
        return t1.S>t2.S;
    }
    void DFS(int T,int S) //DFS预处理。
    {
        for (int a=Head[T];a;a=Edge[a].Next)
        {
            int t=Edge[a].To;
            if (!Deep[t]&&t!=1) //特判。
            {
                Deep[t]=Deep[T]+1;
                f[t][0]=T;
                i[t][0]=Edge[a].S; //类似于f[][],存储往上的最大路。
                DFS(t,S+1);
            }
        }
    }
    void Get_Father() //统计父系。
    {
        for (int b=1;b<=16;b++)
          for (int a=1;a<=n;a++)
          {
            f[a][b]=f[f[a][b-1]][b-1];
            i[a][b]=min(i[a][b-1],i[f[a][b-1]][b-1]);
          }
    }
    int Get_Same(int T,int S) //调整深度。
    {
        for (int a=0;a<=16;a++)
          if ((1<<a)&S) //神奇的位运算比较大小。
          {
            Sum=min(Sum,i[T][a]);
            T=f[T][a];
          }
        return T;
    }
    int LCA(int t1,int t2) //倍增LCA。
    {
        if ((t1!=1&&!Deep[t1])||(t2!=1&&!Deep[t2])) //特判,此节点不在树中。
          return -1;
        Sum=1000000000;
        if (Deep[t1]<Deep[t2])
          swap(t1,t2);
        t1=Get_Same(t1,Deep[t1]-Deep[t2]);
        if (t1==t2) //根节点。
          return Sum;
        for (int a=16;a>=0;a--)
          if (f[t1][a]!=f[t2][a])
          {
            Sum=min(Sum,min(i[t1][a],i[t2][a])); //一样在更新。
            t1=f[t1][a];
            t2=f[t2][a];
          }
        return min(Sum,min(i[t1][0],i[t2][0]));
    }
    int main() //最大生成树+倍增LCA,蒟蒻搞了一上午!
    {
        memset(i,0x3f,sizeof(i));
        scanf("%d%d",&n,&m);
        for (int a=0;a<m;a++)
          scanf("%d%d%d",&Map[a].X,&Map[a].Y,&Map[a].S);
        sort(Map,Map+m,Rule);
        for (int a=0;a<m;a++) //Kruskal算法。
        {
            int t1=Find(Map[a].X);
            int t2=Find(Map[a].Y);
            if (t1!=t2)
            {
                Add(Map[a].X,Map[a].Y,Map[a].S);
                Add(Map[a].Y,Map[a].X,Map[a].S);
                F[t2]=t1;
                Number++;
                if (Number==n-1)
                  break;
            }
        }
        DFS(1,0); //倍增LCA。
        Get_Father();
        scanf("%d",&m);
        for (int a=0;a<m;a++)
        {
            int t1,t2;
            scanf("%d%d",&t1,&t2);
            printf("%d
    ",LCA(t1,t2));
        }
        return 0;
    }
  • 相关阅读:
    5.对象创建型模式-原型PROTOTYPE
    4.对象创建型模式-工厂方法
    3.对象创建型模式-生成器
    一个小应用的dbcp和c3p0配置实例
    利用 java.lang.Runtime.addShutdownHook() 钩子程序,保证java程序安全退出
    初探maven插件机制
    【转载】Git push时重复输入用户名密码的问题
    【转载】 ERROR 1045 (28000): Access denied for user root@localhost (using password: NO)
    【转载】[Java]读取文件方法大全
    【原创】iframe与父页面之间,变量、方法互相调用
  • 原文地址:https://www.cnblogs.com/Ackermann/p/5654096.html
Copyright © 2020-2023  润新知