hihocoder1093 SPFA算法模板

来源:互联网 发布:森系服装品牌 知乎 编辑:程序博客网 时间:2024/06/01 09:55

一:背景

SPFA(Shortest Path Faster Algorithm)算法,是西南交通大学段凡丁于 1994 年发表的,其在 Bellman-ford 算法的基础上加上一个队列优化,减少了冗余的松弛操作,是一种高效的最短路算法。

二:算法过程

设立一个队列用来保存待优化的顶点,优化时每次取出队首顶点 u,并且用 u 点当前的最短路径估计值dist[u]对与 u 点邻接的顶点 v 进行松弛操作,如果 v 点的最短路径估计值dist[v]可以更小,且 v 点不在当前的队列中,就将 v 点放入队尾。这样不断从队列中取出顶点来进行松弛操作,直至队列空为止。(所谓的松弛操作,简单来说,对于顶点 i,把dist[i]调整更小或更大。更多解释请参考百科:松弛操作)

而其检测负权回路的方法也很简单,如果某个点进入队列的次数大于等于 n,则存在负权回路,其中 n 为图的顶点数。



一个图文详解非常详细的博客:http://www.360doc.com/content/13/1208/22/14357424_335569176.shtml

比较简单的算法,容易理解。

#1093 : 最短路径·三:SPFA算法

时间限制:10000ms
单点时限:1000ms
内存限制:256MB

描述

万圣节的晚上,小Hi和小Ho在吃过晚饭之后,来到了一个巨大的鬼屋!

鬼屋中一共有N个地点,分别编号为1..N,这N个地点之间互相有一些道路连通,两个地点之间可能有多条道路连通,但是并不存在一条两端都是同一个地点的道路。

不过这个鬼屋虽然很大,但是其中的道路并不算多,所以小Hi还是希望能够知道从入口到出口的最短距离是多少?

提示:Super Programming Festival Algorithm。

输入

每个测试点(输入文件)有且仅有一组测试数据。

在一组测试数据中:

第1行为4个整数N、M、S、T,分别表示鬼屋中地点的个数和道路的条数,入口(也是一个地点)的编号,出口(同样也是一个地点)的编号。

接下来的M行,每行描述一条道路:其中的第i行为三个整数u_i, v_i, length_i,表明在编号为u_i的地点和编号为v_i的地点之间有一条长度为length_i的道路。

对于100%的数据,满足N<=10^5,M<=10^6, 1 <= length_i <= 10^3, 1 <= S, T <= N, 且S不等于T。

对于100%的数据,满足小Hi和小Ho总是有办法从入口通过地图上标注出来的道路到达出口。

输出

对于每组测试数据,输出一个整数Ans,表示那么小Hi和小Ho为了走出鬼屋至少要走的路程。

样例输入
5 10 3 51 2 9972 3 5053 4 1184 5 543 5 4803 4 7965 2 7942 5 1465 4 6042 5 63
样例输出
172
#include <bits/stdc++.h>using namespace std;const int AX = 1e5+666;const int INF = 1234567;int dis[AX];int n,m,s,t;vector<int>vec[AX];vector<int>wei[AX];int vis[AX];queue<int>que;void SPFA(){memset(vis,0,sizeof(vis));for(int i=1;i<=n;i++){dis[i] = INF;}que.push(s);dis[s] = 0;vis[s] = 1;while(!que.empty()){int u = que.front();que.pop();vis[u] = 0;for(int i=0;i<vec[u].size();i++){if(wei[u][i] != INF){if(dis[u] + wei[u][i] < dis[vec[u][i]]){dis[vec[u][i]] = dis[u] + wei[u][i];if(!vis[vec[u][i]]){que.push(vec[u][i]);vis[vec[u][i]] = 1;}}}}}} int main(){scanf("%d%d%d%d",&n,&m,&s,&t);int x,y,w;while(m--){scanf("%d%d%d",&x,&y,&w);vec[x].push_back(y);vec[y].push_back(x);wei[x].push_back(w);wei[y].push_back(w);}SPFA();printf("%d\n",dis[t]);return 0;}

/***   别人的模板* author 刘毅(Limer)* date   2017-05-28* mode   C++*/#include<iostream>    #include<queue>#include<stack>using namespace std;int matrix[100][100];  //邻接矩阵bool visited[100];     //标记数组int dist[100];         //源点到顶点i的最短距离int path[100];         //记录最短路的路径int enqueue_num[100];  //记录入队次数int vertex_num;        //顶点数int edge_num;          //边数int source;            //源点bool SPFA(){    memset(visited, 0, sizeof(visited));    memset(enqueue_num, 0, sizeof(enqueue_num));    for (int i = 0; i < vertex_num; i++)    {        dist[i] = INT_MAX;        path[i] = source;    }    queue<int> Q;    Q.push(source);    dist[source] = 0;    visited[source] = 1;    enqueue_num[source]++;    while (!Q.empty())    {        int u = Q.front();        Q.pop();        visited[u] = 0;        for (int v = 0; v < vertex_num; v++)        {            if (matrix[u][v] != INT_MAX)  //u与v直接邻接            {                if (dist[u] + matrix[u][v] < dist[v])                {                    dist[v] = dist[u] + matrix[u][v];                    path[v] = u;                    if (!visited[v])                    {                        Q.push(v);                        enqueue_num[v]++;                        if (enqueue_num[v] >= vertex_num)                            return false;                        visited[v] = 1;                    }                }            }        }    }    return true;}void Print(){    for (int i = 0; i < vertex_num; i++)    {        if (i != source)        {            int p = i;            stack<int> s;            cout << "顶点 " << source << " 到顶点 " << p << " 的最短路径是: ";            while (source != p)  //路径顺序是逆向的,所以先保存到栈            {                s.push(p);                p = path[p];            }            cout << source;            while (!s.empty())  //依次从栈中取出的才是正序路径            {                cout << "--" << s.top();                s.pop();            }            cout << "    最短路径长度是:" << dist[i] << endl;        }    }}int main(){    cout << "请输入图的顶点数,边数,源点:";    cin >> vertex_num >> edge_num >> source;    for (int i = 0; i < vertex_num; i++)        for (int j = 0; j < vertex_num; j++)            matrix[i][j] = INT_MAX;  //初始化matrix数组    cout << "请输入" << edge_num << "条边的信息:\n";    int u, v, w;    for (int i = 0; i < edge_num; i++)    {        cin >> u >> v >> w;        matrix[u][v] = w;    }    if (SPFA())        Print();    else        cout << "Sorry,it have negative circle!\n";    return 0;}