最短路算法-spfa

前言:存在负权边时dijkstra算法不可使用,存在无限死循环,因此引入spfa算法。

详解:spfa求解单源最短路,能进行负权环的判断,存在负权环不能输出最短路,反之可行。

实现方法:建立一个队列,初始时队列里只有起始点,然后执行松弛操作,用队列里有的点去刷新起始点到所有点的最短路,如果刷新成功且被刷新点不在队列中则把该点加入到队列最后。重复执行直到队列为空。

时间复杂度O(MN)

本博客主要以知识点复习为主

#include<bits/stdc++.h>
using namespace std;

const int Max=100;     //点的数目
const int INF=1e9;     //设置最大值
struct node
{
    int to;
    int val;
};
node temp;
queue<int>check;       //存储点集
vector<node>edge[Max]; //记录边的数据
int dis[Max];          //起点到达各点最短路
int vis[Max];          //记录点是否在队列里
int cnt[Max];          //记录点被压进队列次数
int path[Max];         //记录路径
int n,m;               //点与边数目
int flag;              //设置负环是否存在

void init()  //初始化路径
{
    for(int i=0;i<Max;i++)
    {
        edge[i].clear();
        dis[i]=INF;
        path[i]=-1;
        cnt[i]=0;
    }
    while(check.empty()==0)
    {
        check.pop();
    }
}

void read()  //读入数据
{
    int u,v,w;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&u,&v,&w);
        temp.val=w;
        temp.to=v;
        edge[u].push_back(temp);
        temp.val=w;
        temp.to=u;
        edge[v].push_back(temp);
    }
}

int spfa(int s)  //更新最小路径
{
    check.push(s);
    dis[s]=0;
    vis[s]=1;
    cnt[s]=1;  //设置起点入队列次数
    path[s]=-1;
    while(check.empty()==0)
    {
        int temp=check.front();
        int cub=edge[temp].size();
        for(int i=0;i<cub;i++)
        {
            node t=edge[temp][i];
            if(dis[temp]+t.val<dis[t.to])
            {
                path[t.to]=temp;
                dis[t.to]=dis[temp]+t.val;
                if(vis[t.to]==0)  //判断是否已经入列
                {
                    check.push(t.to);
                    vis[t.to]=1;
                    cnt[t.to]++;
                    if(cnt[t.to]>n-1)  //存在负环退出
                    {
                        return 0;
                    }
                }
            }
        }
        check.pop();
        vis[temp]=0;
    }
    return 1;
}

void output(int e)  //打印路径
{
    if(path[e]==-1)  //路径起始点
    {
        printf("%d",e);
    }
    else
    {
        output(path[e]);
        printf("->%d",e);
    }
}

int main()
{
    while(scanf("%d%d",&n,&m)!=-1)
    {
        init();
        read();
        flag=spfa(1);  //以起点1为例
        if(flag==0)
        {
            printf("存在负环\n");
        }
        else
        {
            printf("%d\n",dis[n]);  //以终点n为例
            output(n);
            printf("\n");
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/SMyName/article/details/81452454