类Floyd算法

类Floyd算法

含义

类Floyd算法故名思意就是和Floyd算法类似的一种最短路算法,可以用于求有负环的图的多源最短路问题

此算法区别于传统Floyd算法的特点——利用两点之间经过边的数量来进行 dp 转移。所以该算法可以解决负环图中的任意两点间最短路问题。理论复杂度 \(O(Nn^3)\) ,倍增优化后复杂度 \(O(log_N n^3)\)

首先用动态规划的角度去思考问题,设计状态转移方程

\(dis [k] [i] [j]\) 表示从 \(i\)\(j\) ,恰好经过 \(k\) 条边的最短路径

状态转移方程:

\[d[a+ b , i , j] = min( d[a , i , k ] + d[b , k , j] ) \]

优化思路

仔细观察这个过程不难发现,如果我们知道 \(dis[k][i][x]\)\(dis[k][x][j]\) 就可以得出 \(dis[2k][i][j]\) ,即知道任意 \(dis_{k,i,j}\) 即可求出任意 \(dis_{2k,i,j}\) ,那么同样已知 \(dis_{2k,i,j}\) 即可求出任意 \(dis_{4k,i,j}\) ,诸如此类,利用倍增的思想,我们可以求解出 \(dis_{2^n,i,j}\) 。同样该转移方式满足结合律,利用快速幂可以将复杂度优化到 \(O(log_Nn^3)\)

实现方式

实现方式就很简单了,可以类比矩阵乘法的实现方式来实现。(前置知识,矩阵快速幂,矩阵乘法 )

例题 ACwing345.牛站

题目思路很清晰,即求出类最短路算法中 \(dis [N] [i] [j]\)

code

#include <bits/stdc++.h>
using namespace std ;
const int maxn = 210 , INF = 0x3f3f3f3f ; 
int t , n , m , S , E ;
int g[210][210] , res[210][210] ; 
void mul(int c[][maxn] , int a[][maxn] , int b[][maxn])
{
    static int T[maxn][maxn] ; 
    memset(T , 0x3f , sizeof(T)) ; 
    for(int k = 1 ; k <= n ; k++ )
        for(int i = 1 ; i <= n ; i++ )
            for(int j = 1 ; j <= n ; j++ )
                T[i][j] = min(T[i][j] , a[i][k] + b[k][j]) ; 
    memcpy(c , T , sizeof(T)) ; 
}
void KSM()
{
    memset(res , 0x3f , sizeof(res)) ; 
    for(int i = 1 ; i <= n ; i++)   res[i][i] = 0 ; 
    while( t )
    {
        if(t & 1 )  mul(res , res , g) ;
        mul(g , g , g) ; 
        t >>= 1 ; 
    }
}
signed main()
{
    cin >> t >> m >> S >> E ; 
    memset(g , 0x3f , sizeof(g)) ; 
    map<int , int > q ; 
    if(! q.count(S))    q[S] = ++n ;
    if(! q.count(E))    q[E] = ++n ; 
    S = q[S] , E = q[E] ; 
    while( m-- )
    {
        int u , v , w ; 
        cin >> w >> u >> v ;
        if(! q.count(u))    q[u] = ++n ;
        if(! q.count(v))    q[v] = ++n ; 
        u = q[u] , v = q[v] ; 
        g[u][v] = g[v][u] = min(g[u][v] , w) ; 
    }
    KSM() ; 
    cout << res[S][E] ; 
    return 0 ; 
}
posted @ 2022-04-20 22:40  Simon_...sun  阅读(75)  评论(0)    收藏  举报