SPFA算法总结

                                                                                                 SPFA算法

一、spfa算法

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

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

二、模板

 

#include 
#include 
#include 
#include 
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 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  
#include 
#include 
#define Maxn 100
#define Maxm 10000
#define Max 10000
int 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 
#include 
#include 
#include 
#define Maxn 100
#define Maxm 10000
#define Max 10000
using 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  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");
    }
}

 

 

 

 

 

 

你可能感兴趣的:(算法设计)