浅谈图论

  • 多源最短路算法(Floyd)

    说到最短路,就不得不提到松弛。
    所谓松弛,就是当存在wu,v>wu,k+wk,v时,令wu,v=wu,k+wk,v
    一般来说,松弛操作后,我们会用松弛后的边不断松弛其他边,而这,就是大部分最短路算法的思路。
    思考一下,若用DP的思想考虑,那么我们易设出状态fi,j表示从ij的最短路,但是这个状态显然具有后效性,因为我们显然无法一遍就能转移出fi,j的正确结果,需要不断对其他边进行松弛操作才能得出最后答案,所以同为fi,j的值在不同阶段会有不同的值。
    那么考虑加一维表示松弛阶段,则最显然表示松弛阶段的方式是边,然而边太多且一个边能松弛其他边的数量及其有限,故考虑点。
    则设fk,i,j为只考虑前k个点时,从ij的最短路。
    那么可以推出转移式fk,u,v=min(fk,u,v,fk1,u,k+fk1,k,v)
    不断枚举k,然后枚举所有i,j,用k这个端点去更新它们。
    观察到fk,i,j的值只与fk1,i,j有关,故可以用滚动数组压成二维。
    代码如下:
for (int k = 1; k <= n; ++k) 
        for (int u = 1; u <= n; ++u)
            for (int v = 1; v <= n; ++v)  f[u][v] = min(f[u][v], f[u][k] + f[k][v]); `
  • 单源最短路算法(SPFA)

    单源最短路只求从一个点出发到达其他点的最短路,故我们不需要把每条边都松弛一遍。
    所以很自然地,我们可以想到从与出发点s相连的边开始,不断用已经知道的点来松弛其他边,直到再也无法松弛为止,这就是Bellman-Ford单源最短路算法的思路,但这显然很暴力,所以我们需要优化。
    不难发现,我们似乎不需要那么多次松弛,我们只需要让每条被松弛的两点间路径再去松弛经过此两点间路径的路径就可以得出每条最短路。
    所以考虑代码实现,设disv表示从起点sv的最短路,我们只需要将起点s压入队列,对于队列中每个点u和其到达的下一个点v来说,如果出现了disv>disu+wu,v的情况,那么就表示disv可以被松弛,并且与v有关的路径可能有disv路径的参与会更短,那么对disv进行松弛操作并把v压入队列进行处理,如果队列中没有点了,就说明最短路的搜索已经完成了。
    值得注意的是,显然一个点大概率会被入队多次,所以为了尽可能地降低时间复杂度,我们可以用一个数组visu来表示点u是否在队列内,若是在的话就不用再次入队了。显然,当我们处理完一个点u时,需要使visu=0
    这个算法被称作队列优化的Bellman-Ford算法,也被称作SPFA(Shortest Path Faster Algorithm)
    代码如下:
void spfa(int st) {
    q[++tl] = st, dis[st] = 0, vis[st] = 1;
    while (hd <= tl) {
        int u = q[hd++];
        for (int i = head[u]; i; i = nxt[i]) {
            int v = to[i];
            if (dis[v] > dis[u] + w[i]) {
                dis[v] = dis[u] + w[i];
                if (!vis[v])  q[++tl] = v, vis[v] = 1;
            }
        }
        vis[u] = 0;
    }
}
posted @   Kazdale  阅读(15)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示