SPFA算法(Shortest Path Faster Algorithm),也是求解单源最短路径问题的一种算法,用来解决:给定一个加权有向图G和源点s,对于图G中的任意一点v,求从s到v的最短路径。 SPFA算法是Bellman-Ford算法的一种队列实现,减少了不必要的冗余计算,他的基本算法和Bellman-Ford一样,并且用如下的方法改进: 1、第二步,不是枚举所有节点,而是通过队列来进行优化 设立一个先进先出的队列用来保存待优化的结点,优化时每次取出队首结点u,并且用u点当前的最短路径估计值对离开u点所指向的结点v进行松弛操作,如果v点的最短路径估计值有所调整,且v点不在当前的队列中,就将v点放入队尾。这样不断从队列中取出结点来进行松弛操作,直至队列空为止。 2、同时除了通过判断队列是否为空来结束循环,还可以通过下面的方法: 判断有无负环:如果某个点进入队列的次数超过V次则存在负环(SPFA无法处理带负环的图)。(来自NOCOW)
HDU 2544 模板测试专用
#include
#include
#include
#include
//邻接表储存比较好,时间和空间效率上都优于矩阵,不过实现略微复杂
struct node{
int end, weight;
node *next;
};
const int inf = 0xfffff;
node ver[200];
int n, m; //n为顶点数,m为边数
int dis[200], vis[200], count[200]; //count记录顶点入队列次数,若一个顶点入队大于n次,则存在负环
void insert(int a, int b, int w){
node *p = (node *)malloc(sizeof(node));
p->end = b, p->weight = w;
p->next = ver[a].next;
ver[a].next = p;
}
void initi(int n){
int i;
dis[1] = 0; //1作为起点
memset(vis, 0, sizeof(vis));
memset(count, 0, sizeof(count));
ver[1].next = NULL;
for (i = 2;i <= n;i++){
dis[i] = inf;
ver[i].next = NULL;
}
}
int SPFA(){
std::queue p;
p.push(1);
count[1]++;
vis[1] = 1;
while (!p.empty()){
int s = p.front();
p.pop();
vis[s] = 0;
for (node *q = ver[s].next;q != NULL;q = q->next) //对出队元素进行松弛
if (dis[q->end] > dis[s] + q->weight){
dis[q->end] = dis[s] + q->weight;
if(!vis[(q->end)]){
p.push(q->end);
vis[(q->end)] = 1;
count[q->end]++;
}
if (count[q->end] > n) //判断是否存在负环
return -1;
}
}
return dis[n];
}
int main(){
while (scanf("%d%d", &n, &m)){
int i,a,b,w;
if (n == 0&&m == 0)
break;
initi(n);
for (i = 0;i < m;i++){
scanf("%d%d%d", &a, &b, &w);
insert(a, b, w);
insert(b, a, w);
}
printf("%d\n", SPFA());
}
return 0;
}
静态链表版(模拟链表),用个namespace封装比较好
#include
#include
#include
#include
using namespace std;
const int N = 101;
const int INF = 0xfffff;
int n, m;
namespace graph{
struct SPFA{
int dis[N], vis[N], head[N], it, cnt;
struct node{
int end, weight;
int next;
}edge[N * N];
void addedge(int a, int b, int w){
edge[cnt].end = b;
edge[cnt].weight = w;
edge[cnt].next = head[a];
head[a] = cnt++;
}
void initi(int n, int start){
int i;
cnt = 0;
memset(vis, 0, sizeof(vis));
memset(head, -1, sizeof(head));
for(i = 1;i <= n;i++)
dis[i] = INF;
dis[start] = 0;
}
int shortest_path(int start, int end){
queue p;
p.push(start);
vis[start] = 1;
while(!p.empty()){
int s = p.front();
p.pop();
vis[s] = 0;
for(it = head[s];it != -1;it = edge[it].next){
int to = edge[it].end;
if(dis[to] > dis[s] + edge[it].weight){
dis[to] = dis[s]+edge[it].weight;
if(!vis[to]){
p.push(to);
vis[to] = 1;
}
}
}
}
return dis[end];
}
}g;
}
int main(){
int n, m;
while(cin >> n >> m){
int i, a, b, w;
if(!n&&!m)
break;
graph::g.initi(n, 1);
for(i = 0;i < m;i++){
scanf("%d%d%d", &a, &b, &w);
graph::g.addedge(a, b, w);
graph::g.addedge(b, a, w);
}
cout << graph::g.shortest_path(1, n) << endl;
}
return 0;
}