SPFA算法总结

来源:互联网 发布:微信视频强制分享源码 编辑:程序博客网 时间:2024/05/29 14:27

                                                                                                 SPFA算法

一、spfa算法

很多时候,给定的图存在负权边,这时类似Dijkstra等算法便没有了用武之地,而Bellman-Ford算法的复杂度又过高,SPFA算法便派上用场了。

思想:用于求单源最短路径,可以适用于负边权的情况。spfa(Shortest Path Faster Algorithm)算法是bellman-ford算法的队列优化。设立一个先进先出的队列用来保存待优化的结点,优化时每次取出队首结点u,并且用u点当前的最短路径估计值对离开u点所指向的结点v进行松弛操作,如果v点的最短路径估计值有所调整,且 v点不在当前的队列中,就将v点放入队尾。这样不断从队列中取出结点来进行松弛操作,直至队列空为止。

二、模板

#include <iostream>#include <cstdio>#include <cstring>#include <queue>using namespace std;const int N = 105;const int INF = 0x3f3f3f3f;int map[N][N], dist[N];bool visit[N];int n, m;void init() //初始化{    int i, j;    for (i = 1; i < N; i++)    {        for (j = 1; j < N; j++)        {            if (i == j)            {                map[i][j] = 0;            }            else            {                map[i][j] = map[j][i] = INF;            }        }    }}/** * SPFA算法. * 使用spfa算法来求单元最短路径 * 参数说明: * start:起点 */void spfa(int start){    queue<int> Q;    int i, now;    memset(visit, false, sizeof(visit));    for (i = 1; i <= n; i++)    {        dist[i] = INF;    }    dist[start] = 0;    Q.push(start);    visit[start] = true;    while (!Q.empty())    {        now = Q.front();        Q.pop();        visit[now] = false;        for (i = 1; i <= n; i++)        {            if (dist[i] > dist[now] + map[now][i])            {                dist[i] = dist[now] + map[now][i];                if (visit[i] == 0)                {                    Q.push(i);                    visit[i] = true;                }            }        }    }}int main(){    while(scanf("%d%d",&n,&m)!=EOF)    {        init();        while(m--)        {            int a,b,c;            scanf("%d%d%d",&a,&b,&c);            if(map[a][b] > c)            {                map[a][b] = map[b][a] = c;            }        }        spfa(1);        printf("%d\n",dist[n]);    }    return 0;}

//效率最高#include <cstdio> #include <iostream>#include <cstring>#define Maxn 100#define Maxm 10000#define Max 10000int used[Maxn],outqueue[Maxn],head[Maxn],queue[Maxn],low[Maxn],n,m;struct Edge{    int to,w,next;} edge[Maxm];bool SPFA(int start){    int i =0, iq = 0;    used[start] = 1;    queue[iq++] = start;    low[start] = 0;    while (i != iq)    {        int top = queue[i];        used[top] = 0;        outqueue[top]++;//用来判断是否有环路        if (outqueue[top] > n) return false;        for (int k = head[top]; k != -1; k = edge[k].next)//宽搜每条边        {            if (low[edge[k].to] > low[top] + edge[k].w)//对点进行松驰                low[edge[k].to] = low[top] + edge[k].w;            if (!used[edge[k].to])            {                used[edge[k].to] = 1;                queue[iq++] = edge[k].to;            }        }        i++;    }    return true;}int main(){    while (scanf ("%d%d", &n,&m) != EOF)    {        memset (used, 0,sizeof(used));        memset (head, -1,sizeof(head));        memset (outqueue, 0,sizeof(outqueue));        memset (low, Max, sizeof(low));        int k = 0;        while (m--)        {            int a,b,w;            scanf ("%d%d%d", &a, &b, &w);            edge[k].to = b;            edge[k].w = w;            edge[k].next = head[a];            head[a] = k++;        }        if (SPFA(1))            printf ("%d\n", low[n]);        else            printf ("不存在最短\n");    }}

//用stl实现队列#include <cstdio>#include <queue>#include <iostream>#include <cstring>#define Maxn 100#define Maxm 10000#define Max 10000using namespace std;int used[Maxn],outqueue[Maxn],head[Maxn],low[Maxn],n,m;struct Edge{    int to,w,next;} edge[Maxm];bool SPFA (int start){    queue <int> a;    used[start] = 1;    low[start] = 0;    a.push(start);    while (!a.empty())    {        int top = a.front();        a.pop();        outqueue[top]++;        if (outqueue[top] > n) return false;        for (int k = head[top]; k!= -1; k = edge[k].next)        {            if (low[edge[k].to] > low[top] + edge[k].w)                low[edge[k].to] = low[top] + edge[k].w;            if (!used[edge[k].to])            {                used[edge[k].to] = 1;                a.push(edge[k].to);            }        }    }    return true;}int main(){    while (scanf ("%d%d", &n,&m) != EOF)    {        memset (used, 0,sizeof(used));        memset (head, -1,sizeof(head));        memset (outqueue, 0,sizeof(outqueue));        memset (low, Max, sizeof(low));        int k = 0;        while (m--)        {            int a,b,w;            scanf ("%d%d%d", &a, &b, &w);            edge[k].to = b;            edge[k].w = w;            edge[k].next = head[a];            head[a] = k++;        }        if (SPFA(1))            printf ("%d\n", low[n]);        else            printf ("不存在最短\n");    }}