• 任意两点间的最短路 Floyd及其本质


    我们知道在已知起点的情况下,求到其他任何一点的最短路是用dijkstra,那么在一个有向图中,我们想知道任意两点之间的最短路,我们就可以使用floyd,而且这个算法表面看起来非常的简单,就是一个三重循环,如果这个图有N个点,那么复杂度为O(|N|3),代码如下。

    1 for(int k=0;k<n;k++)
    2 for(int i=0;i<n;i++)
    3 for(int j=0;j<n;j++)
    4 d[i][j]=min(d[i][j],d[i][k]+d[k][j]);

    在复杂度这么高的情况下,一般情况下如果不是板子题直接用的话肯定是会超时的,所以我们还是需要了解Floyd是怎么进行的,其实它的本质就是dp。

    其实我从上面的代码中不难看出Floyd是采用状态转移的方式来更新各个点之间的距离的,而这个点就是k,即从i-j之间的最短路是否经过k点,不断的更新从而取得最优解,下面我们详细的说一下。

    假设从顶点i出发,仅经由顶点Vk={1,2,3,···,k}抵达顶点j的最短路径成本为Ak[i,j]。首先,A0[i,j]表示从i到j不经由其他任何顶点,所以其值就等于连接i,j边的权值,如果不存在边时其大小为正无穷,接下来是k=1,2,3,···,|N|的情况,我们需要通过Ak-1来计算Ak,那么我们只需要考虑是否经过k点两种情况。

    如果经过k,则路径会被分为i-k,k-j两个路径,而且这两个路径全都只经过Vk-1,中的顶点,因此Ak=Ak-1[i,k]+Ak-1[k,j]。

    如果不经过k,那就意味着Ak[i,j]只经过i,j及属于Vk-1中的顶点,所以Ak[i,j]=Ak-1[i,j];

    综上所知Ak[i,j]=min(Ak-1[i,j],Ak-1[i,k]+Ak-1[k,j])。

    那么我们接下来看这个题目

    洛谷P1119灾后重建

    在这个题目中,图的状态是随着时间而改变的,在不同的时刻的询问下,任意两点之间的最短路也会发生改变,如果每问一次就用一次Floyd的话,毫无疑问的超时,那我们注意观察题目可以发现,某一个点能不能使用是随着时间变化的,我们在前面提到过,Floyd使用的点是根据k来变化的,及循环内部是用不到k+1及以后的点的,那么因为它的询问根据之间逐渐增加的,所以我们只要根据时间来不断的从更新k内部的点即可。

    下面是完整代码

     1 #include <iostream>
     2 #include <cstring>
     3 #include <string>
     4 #include <algorithm>
     5 #include <queue>
     6 #include <stack>
     7 #include <stdio.h>
     8 #include <cmath>
     9 #include <string.h>
    10 
    11 using namespace std;
    12 #define ll long long
    13 static const int WHITE=0;
    14 static const int GRAY=1;
    15 static const int BLACK=2;
    16 static const int INF=(1<<20);
    17 int N,M,Q;
    18 int time1[205];
    19 int map[205][205];
    20 void floyd(int k)
    21 {
    22     for(int i=0;i<N;i++)
    23     for(int j=0;j<N;j++)
    24     map[i][j]=min(map[i][j],map[i][k]+map[k][j]);
    25     return ;
    26 }
    27 int main()
    28 {
    29     freopen("C:\Users\16599\Desktop\in.txt","r",stdin);
    30     scanf("%d%d",&N,&M);
    31     int now=0;
    32     for(int i=0;i<N;i++)
    33     {
    34         int a;
    35         scanf("%d",&a);
    36         time1[i]=a;
    37     }
    38     for(int i=0;i<=N;i++)
    39     for(int j=0;j<=N;j++)
    40     map[i][j]=((i==j)?0:INF);
    41     for(int m=0;m<M;m++)
    42     {
    43         int i,j,k;
    44         scanf("%d%d%d",&i,&j,&k);
    45         map[i][j]=map[j][i]=k;
    46     }
    47     scanf("%d",&Q);
    48     for(int q=1;q<=Q;q++)
    49     {
    50         int x,y,t;
    51         scanf("%d%d%d",&x,&y,&t);
    52         while(time1[now]<=t&&now<=N)
    53         {
    54             floyd(now);
    55             now++;
    56         }
    57         if(t<time1[x]||t<time1[y]||map[x][y]==INF)
    58         printf("-1
    ");
    59         else
    60         {
    61             printf("%d
    ",map[x][y]);
    62         }
    63     }
    64     return 0;
    65 }
  • 相关阅读:
    Flask Mysql数据库连接
    Flask form前后端交互消息闪现
    Flask block继承和include包含
    Flask filter过滤器
    常规http状态码
    linux搭建hadoop环境
    inline-block布局代码
    JDBC4.0自动加载驱动器类
    用反射模拟Hibernate保存JavaBean
    深入ThreadLocal的内部机制
  • 原文地址:https://www.cnblogs.com/zlhdbk/p/11510840.html
Copyright © 2020-2023  润新知