zoukankan      html  css  js  c++  java
  • 校内比赛 城市交通费

     城市交通费

    题解:

    1.整体思路:

        按照城市繁华度从小到大的枚举顺序跑一遍Floyd

    2.首先我们明确一下:

        城市交通费 = 从城市 i 到城市 j 的路径长度 + 途径城市的最大繁华度

    3.数组变量的意义:

        dis[ i ][ j ] 城市 i 到城市 j 的最短路径长度

               p[ i ] 城市 i 的城市繁华度

           lu[ i ][ j ] 城市 i 到城市 j 的最少城市交通费

                t[ i ] 第 i 最不繁华的城市编号

     4.代码思路:

      (1)读入 n , m , q 

      (2)初始化城市间的最短路径为无穷大(63,也就是 0x3f )

      (3)读入每个点的城市繁华度,并且初始化城市自己到自己的 dis 为 0

      (4)读入边,在有路径的两个城市之间建立一条边,在读入过程中可能会有重边,所以取最小值就好

      (5)初始化城市交通费:

                两个城市之间的城市交通费 = 直连路径 + 这两个城市之间的最大繁华度

      (6)把城市按照城市繁华度从小到大排序(即,t[ ] 排序)  //详情见注释1

      (7)跑Floyd,枚举最外层中间点的时候要按照 t 数组的顺序枚举  //详情见注释2

      (8)q次询问,输出城市交通费 lu [ i ][ j ]

    5.注释

     (1)为什么要把城市按照城市繁华度从小到大排序呢??这个问题也困惑了我好久

              Floyd的原理大家都知道吧?

              也就是选取中间城市 k ,用dis[ i ][ t[ k ] ]+dis[ t[ k ] ][ j ]来松弛 dis[ i ][ j ]

              我们现在排好序了,那么对于任意两个确定的城市 i ,j ,中间点 k 的繁华度一定是在枚举过程中递增的

              所以说在 i -> j 的这条路径中,可能经过的城市只会在 编号为t[ 1 ] ~ t[ k ] 中出现

             Ps:(用t数组表示城市编号是因为排好序之后,t数组的下标和城市编号是不同的(忘了 t 数组是干啥的小可爱请转至 / 代码思路3 /))

             那么当你在更新 lu [ i ][ j ]的时候,由于要计入沿途城市的最大繁华度,所以最大繁华度只有可能在点 i , j , t[ k ] ,这三个城市中选取,而不用枚举所有的沿途城市啦

             对应代码就是

             简而言之,t 数组就是为了后面更新 lu[ i ][ j ]时考虑最大繁华度做准备的

     (2)一开始看下面这两行代码我在思索:哎?如果在代码line1时dis没有被 k 点更新,那么他下一步还是会执行line2代码,但是line2代码不就是默认dis被 t[ k ] 更新了么?这不是矛盾的吗??

            

           

            现实是AC代码没有问题QWQ,考虑一下WHY??

            我们先假设dis没有被 t[ k ] 更新,我们来看line2代码取最小值

            那么对于 lu [ i ][ j ] ,它的 dis[ i ][ j ] 还是原来的数值,城市繁华度一定是在 p[ i ] , p[ j ] 中取最大值,对于dis[i][j]+max(p[i],max(p[j],p[t[k]]))中的dis也是原来的dis值(因为没有更新啊)

           下面分类讨论:

           <1> p[ t[k] ] > p[ i ] , p[ j ] , 那么,line2取最小值的时候一定会取 lu [ i ][ j ] ,那么就 雨 t[k] 无瓜啊,就相当于 line1没有执行

           <2> p[ t[k] ] < p[ i ] , p[ j ] , 那么这个值一定会在 p[ i ],p[ j ]中取一个最大值,仔细思索,这不就是 lu[ i ][ j ]么!!那么就 雨 t[k] 无瓜啊,就相当于 line1没有执行

           得出结论:如果想让 lu[ i ][ j ] 被 t[ k ] ,更新,前提是 dis[ i ][ j ] 被 t[ k ] 更新,所以说,不矛盾

    代码

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<string>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<cstdlib>
    
    using namespace std;
    
    int n,m,q,lu[255][255],p[255],dis[255][255],a,b,c,t[255];
    
    bool cmp(int x,int y)
    {
        return p[x]<p[y];
    }
    
    int main()
    {
    //    freopen("road.in","r",stdin);
    //    freopen("road.out","w",stdout);
        memset(dis,0x3f,sizeof(dis));  //或者memset(dis,63,sizeof(dis)),一样的
        scanf("%d%d%d",&n,&m,&q);
        for(int i=1;i<=n;i++)
        {
            dis[i][i]=0;
            scanf("%d",&p[i]);
            t[i]=i;
        }
          
        sort(t+1,t+n+1,cmp);  //注释1
          
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&a,&b,&c);
            dis[a][b]=min(dis[a][b],c);
            dis[b][a]=min(dis[b][a],c);
        }
        
        
        //初始化两座城市的最少交通费,也就是:两点之间路径+最大繁华度 
        for(int i=1;i<=n;i++)
          for(int j=1;j<=n;j++)
            lu[i][j]=dis[i][j]+max(p[i],p[j]);
        
        
        //跑Floyd 
        for(int k=1;k<=n;k++)
          for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
            {
                dis[i][j]=min(dis[i][j],dis[i][t[k]]+dis[t[k]][j]);  //注释2
                lu[i][j]=min(lu[i][j],dis[i][j]+max(p[i],max(p[j],p[t[k]]))); //注释2
            }
        
        
        for(int i=1;i<=q;i++)  //q次询问 
        {
            scanf("%d%d",&a,&b);
            printf("%d
    ",lu[a][b]);
        }
        
    //    fclose(stdin);
    //    fclose(stdout);    
        return 0;
    }
  • 相关阅读:
    搭建JUnit环境
    搭建日志环境并配置显示DDL语句
    先建表还是先建实体类
    hbm2ddl
    总结与提纲
    常见O/R框架介绍
    hibernate 模拟实现和What is and Why O/R Mapping
    hibernate 注解不给提示
    额,你在main.xml中加了一个id以后,要右键点save,才会将这个id加入到R中,否则是没有的。。。R里的东西是程序自动生成的~~~
    导入android工程@Override报错
  • 原文地址:https://www.cnblogs.com/xiaoyezi-wink/p/11010308.html
Copyright © 2011-2022 走看看