bellman-ford算法的优化spfa算法

来源:互联网 发布:淘宝充王者荣耀点券 编辑:程序博客网 时间:2024/05/16 09:58
bellman-ford算法能够求带负权值的单源最短路径。但是这个算法的时间复杂度(v*E)还是比较高。所以用spfa算法(SPFA无法处理带负环的图)对其优化(利用队列)。
spfa算法的原理:(引用内容)
如何求得最短路径的长度值?首先说明,SPFA是一种单源最短路径算法,所以以下所说的“某点的最短路径长度”,指的是“起点到源点的最短路径长度”。我们记源点为S,由源点到达点i的“当前最短路径”为D[i],开始时将所有D[i]初始化为无穷大,D[S]则初始化为0。算法所要做的,就是在运行过程中,不断尝试减小D[]数组的元素,最终将其中每一个元素减小到实际的最短路径。过程中,我们要维护一个队列,开始时将源点置于队首,然后反复进行这样的操作,直到队列为空:(1)从队首取出一个结点u,扫描所有由u结点可以一步到达的结点,具体的扫描过程,随存储方式的不同而不同;(2)一旦发现有这样一个结点,记为v,满足D[v] > D[u] + w(u, v),则将D[v]的值减小,减小到和D[u] + w(u, v)相等。其中,w(u, v)为图中的边u-v的长度,由于u-v必相邻,所以这个长度一定已知(不然我们得到的也不叫一个完整的图);这种操作叫做松弛。
伪代码:
算法描述
输入设L是用来表示有向图G=(V,E)的邻接表,邻接表元素l是有向图各边的权值,输入各边的权值l(v,k)建立邻接表L.
输出设D数组是记录当前从源点到其余各点的最短路径的值,初始化时D数组的每个元素都为最大值,经过SPFA算法D数组输出各点的最短路径值。
算法的形式算法描述及注释:
1    begin      //算法开始
2    for each v in V do
             Begin
                    For each k∈L[v] do read (l(v,k)); //读入每条边的权值到邻接表
                    QM[v]=0;      //初始化每个顶点是否在队里的标志数组
                    D[v]=MAX;//将最短路径数组初始化为最大值
             End;
3          queue<-v0;
QM[v0]=1;                  //源点v0入queue队
4    D[v0]=0;                  //源点到源点本身的路径值赋值为零
5    while queue not empty do
             Begin
                    W<-queue;    //从queue中取出一个点w
                    QM[w]=0;     //w点出队后,其标志数组元素改为零,表示w点不在队列
6                                      for each j∈L[w] do
7                if D[j]>D[w]+l(w,j) then
                           begin
8                                D[j]=D[w]+l(w,j)  //判断经过w点到j点的路径是比原来的路径D[j]更短后,对j点的路径进行优化
                                  If QM[j]==0 then //只有d[j]的最短路径变化了,j后面的路径才可能会变短。(注意是可能会,尽管如此,我们也要让它入列)
                                  Begin
                                         Queue<-j;
                                         QM[j]=1;       //当j点不在队列里,j入队,并且将QM[j]标志置为1表示j已入队
                                  End
                           End
            End;
9          for each v in V do
begin
             write(D[v]);
end; //优化完成后,D数组存放的就是从源点到各点的最短路径值,可以输出结果
10   end.
 
举个例子:
  一个有向图G ,
 1到2权值为5
 1->3    7
 2->3    -2
 2->4    3
 3->4    4
求源点vo到各顶点的最短路径
代码如下:
#include <iostream>#include <vector>#include <queue>#define mx 99999#define vmax 20using namespace std;int vn ;int v0 ;typedef struct{ int v , w;}edge;vector<edge>g[20] ;int dist[vmax] ;int visited[vmax] ;void spfa(){ for(int i = 1; i <= vn; i ++)  dist[i] = mx ; dist[v0] = 0 ; queue<int>s ; visited[v0] = 1 ; s.push(v0); while(!s.empty()) {  int u = s.front();  s.pop();  int temp ;  visited[u] = 0 ;  for(int i = 0; i < (int)g[u].size(); i ++)  {   temp = g[u][i].w ;   if(dist[u] != mx && dist[g[u][i].v] > dist[u] + temp)   {    dist[g[u][i].v] = dist[u] + temp ;     if(visited[g[u][i].v] == 0)     {      s.push(g[u][i].v) ;      visited[g[u][i].v] = 1 ;     }   }  } }}int main(){ int m , weight, x , y; cin >> vn >> m ; edge temp ; for(int i = 0; i < m; i ++) {  cin >> x >> y >> weight ;  temp.v = y ;  temp.w = weight ;  g[x].push_back(temp); } int t ; cin >> v0 ;  spfa(); while(cin >> t ) {  cout << dist[t] << endl ; } return 0 ;}

  假若1为源点结果为
 dist[2] = 5
 dist[3] = 3 
 dist[4] = 7
spfa算法还有优化要。大家一起努力吧!

原创粉丝点击