图论算法----最短路径SPFA算法详解

一、题目描述

SPFA算法

题目描述

有向图的单源点最短路径问题。源点编号为1,终点编号为n。

输入

第1行:2个空格分开的整数n(2<=n<=5000)和m(10<=m<=500000),分别表示图的顶点数和边数。

第2..m+1行:每行3个空格分开的整数i,j, w。i表示一条边的起点,j表示终点, w表示权值。

输出

第1行:1个整数,表示最小距离

样例输入

样例1:
4 7
1 2 68
1 3 19
1 4 66
2 3 23
3 4 65
3 2 57
4 1 68
样例2:
3 3
1 2 -7
2 3 4
3 1 2

样例输出

样例1:
66
样例2:
No Solution


二、算法分析

在看算法分析时,请保证自己对题目已经十分熟悉)


该算法比较复杂,需要读者具有一定的基础,了解队列的一些用法)



这种题目是典型的最短路径问题,可以用许多算法来解决,但是看了数据范围之后......只有SPFA能够解决。

知道了用SPFA算法, 那我们就来看看SPFA的思路

SPFA是Bellman-Ford的升级版,因为Bellman-Ford里有许多不必要的计算,所以SPFA就利用队列来进行了时间复杂度的优化。

SPFA算法全过程:

1、将起点加入队列,while循环开始。

2、从队列中取出一个元素,for循环开始。

3、用它的最短路径来更新与它相邻的点最短路径,如果有更新成功的,就将其入队

4、for循环结束

5、当队列为空时,while循环结束。

时间复杂度为O(kE),k为常数,大约为2,E为边数,一个接近完美的算法。

算法的总体结构有点像BFS(广搜),但是SPFA中不会判重,就是一个点有可能会多次入队。

看起来SPFA的思路很简单,但是实践起来就不同了。


三、题目分析

(在看题目分析时,请大家做好心理准备


看完题目后,相信大家对程序的框架已经搭好了,大概是这样的:

初始化+SPFA+负权回路判断

但是仔细一看,这些都是难点。

1、初始化:

(1)、将dis数组清为最大值,dis[1]=0;

(2)、将输入的边进行排序(写cmp函数)

(3)、计算每一个点的出边数和对应的起始位置,为SPFA做准备

2、SPFA

(1)、取出一个点

(2)、判断是否有出边

(3)、进行连接点最短路径的更新

3、负权回路判断

这个比较简单,用一个pd数组,一个点入队一次就pd[该点编号]++,

如果超过了pd[该点编号]总点数,就输出“No Solution”。

AC代码:

#include
#include
#include
#include
using namespace std;
queue  q;
int dis[5005],out[5005][2],n,m,pd[5005];
struct node{
    int cd,s,t;
}w[500005];
bool cmp(node a,node b){
    if(a.sb.s) return 0;
    else if(a.tn){
                        printf("No Solution");
                        return 0;
                    }
                }
            }
        }
    }
    printf("%d",dis[n]);
}



 

你可能感兴趣的:(C++,图论,C++图论算法详解)