Bellman-ford,SPFA,Flord算法

Bellman-Ford算法

Dijstra算法可以很好地解决无负权图的最短路径问题,但如果出现了负权边,Dijstra算法会失效。
Bellman-Ford和Dijstra一样,也可以解决单源最短路径问题,同时能处理有负权边的情况。

由于Bellman-Ford算法需要遍历所有边,所以使用邻接表会比邻接矩阵方便

struct Node{
    int v,dis;//v为邻接边的目标顶点,dis为邻接边的边权
};
vector<Node> Adj[maxv]; //图G的邻接表
int n;//n为顶点数,maxv为最大顶点数
int d[maxv]; //起点到达各边的最短路径长度
bool Bellman(int s){
    fill(d,d+maxv,inf);
    d[s]=0;
    for(int i=0;i<n-1;i++){
        for(int u=0;u<n;u++){
            for(int j=0;j<Adj[u].size();j++){
                int v=Adj[u][j].v;
                int dis=Adj[u][j].dis;
                if(d[u]+dis<d[v]){
                    d[v]=d[u]+dis;
                }
            }
        }
    }
    // 以下为判断负环的代码
    for(int u=0;u<n;u++){
        for(int j=0;j<Adj[u].size();j++){
            int v=Adj[u][j].v;
            int dis=Adj[u][j].dis;
            if(d[u]+dis<d[v]){
                return false;
            }
        }
    }
    return true;
}

由于Bellman-Ford算法的时间复杂度达到了O(ve),这并不如意,所以需要进行优化,
Bellman-Ford的每轮操作都需要操作所有边,这其中会有大量无意义操作,严重影响了算法性能。
由于,只有当某个顶点u的d[u]值改变时,从它出发的邻接点v的d[v]值才有可能被改变。
所以可以如下优化:
建立一个队列,每次将队首顶点u取出,然后对从u出发的所有边u->v进行松弛操作,
即判断d[u]+length[u->v]

SPFA算法

上述被优化后的算法即为SPFA算法,期望时间复杂度为O(ve)
但如果图中有从源点可达的负环,则SPFA的时间复杂度又会退化为O(ve)

vector<Node> ADj[maxv];
int n,d[maxv],num[maxv];
bool inq[maxv];
bool SPFA(int s){
    memset(inq,false,sizeof(inq));
    memset(num,0,sizeof(num));
    fill(d,d+maxv,inf);
    queue<int> q;
    q.push(s);
    inq[s]=true;
    num[s]++;
    d[s]=0;
    while(q.empty()){
        int u=q.front();
        q.pop();
        inq[u]=false;
        for(int j=0;j<Adj[u].size();j++){
            int v=Adj[u][j].v;
            int dis=Adj[u][j].dis;
            if(d[u]+dis<d[v]){
                d[v]=d[u]+dis;
                if(!inq[v]){
                    q.push(v);
                    inq[v]=true;
                    num[v]++;
                    if(num[v]>=n) return false;
                }
            }
        }
    }
    return true;
}

Flord算法

Flord算法用来解决全源最短路问题。
即对給定的图G(v,e),求任意两点u,v之间的最短路径长度,时间复杂度为O(n^3)所以顶点数要限制约在200以内。
用邻接矩阵来实现Flord算法比较合适。

#include<cstdio>
#include<algorithm>
using namespace std;
const int inf =0x3f3f3f3f;
const int maxv =200;
int n,m;
int dis[maxv][maxv];
void Flord(){
    for(int k=0;k<n;k++){
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                if(dis[i][k]!=inf&&dis[k][j]!=inf&&dis[i][k]+dis[k][j]<dis[i][j]){
                    dis[i][j]=dis[i][k]+dis[k][j];
                }
            }
        }
    }
}
int main()
{
    int u,v,w;
    fill(dis[0],dis[0]+maxv*maxv,inf);
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++){
        dis[i][i]=0;
    }
    for(int i=0;i<m;i++){
        scanf("%d%d%d",&u,&v,&w);
        dis[u][v]=w;
    }
    Flord();
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            printf("%d ",dis[i][j]);
        }
        printf("\n");
    }
    return 0;
}
    原文作者:Bellman - ford算法
    原文地址: https://blog.csdn.net/hy971216/article/details/80258492
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞