spfa算法

来源:互联网 发布:中小企业数据库 编辑:程序博客网 时间:2024/05/16 19:34

求单源最短路的SPFA算法的全称是:Shortest Path Faster Algorithm。

简单的说就是队列优化的bellman-ford

在路径中存在负权边是 dijkstra 就没法使用了 ,这是就可以SPFA 了

但是当有负权的环是 就没有最短路,spfa 可以判断是否有负权环,如果没有就可以求出最短路。。


期望的时间复杂度O(ke), 其中k为所有顶点进队的平均次数,可以证明k一般小于等于2。  

实现方法:建立一个队列,初始时队列里只有起始点,再建立一个表格记录起始点到所有点的最短路径(该表格的初始值要赋为极大值,该点到他本身的路径赋为0)。然后执行松弛操作,用队列里有的点去刷新起始点到所有点的最短路,如果刷新成功且被刷新点不在队列中则把该点加入到队列最后。重复执行直到队列为空


简单说就是把源点放入队列,然后松弛这个点相连的点,如果松弛成功就把这个点放入队列,用一个数组记录每个点是否在队列中,在一次取出队列中的点,在松弛相连的点,如果松弛成功,就判断这个点是不是在队列中,如果不再队列中就把这个点放入队列(点可能多次进入队列

spfa 可以判断有无负权环,只需 记录每个点进队的次数,如果超过了 n-1 就有负权环,因为每个点松弛的次数不可能超多n-1

#include "iostream"#include "vector"#include "queue"#include "stack"#include "fstream"using namespace std;struct edge{int u;int v;int weight;};const int maxnum = 20;//节点数目最大值std::vector<edge> E[maxnum];//边的数组std::vector<int> dist;//到source的距离std::queue<int> q;//队列,用于存储在SPFA算法中的需要松弛的节点  std::vector<int> visited;//用于判断该节点是否已经在队列中std::vector<int> count;//记录入队次数,超过vertexnum则退出  std::vector<int> path;//节点的前继int vertexnum;//节点数int edgenum;//边数const int maxint = 10000;//权重最大值void initialvector(){// 初始化dist.resize(vertexnum,maxint);visited.resize(vertexnum,0);count.resize(vertexnum,0);path.resize(vertexnum,-1);}void getData(){//获取数据ifstream in("data");in>>vertexnum>>edgenum;initialvector();int from,to;double w;int i = 0;while(in>>from>>to>>w){edge temp;temp.u = from;temp.v = to;temp.weight = w;E[from].push_back(temp);}}bool relax(int u,int v,int weight){if(dist[v] > dist[u] + weight){dist[v] = dist[u] + weight;return true;}return false;}bool spfa(const int source){for(int i = 0;i < vertexnum;i++){dist[i] = (i == source)?0:maxint;}q.push(source);visited[source] = 1;count[source]++;while(!q.empty()){int front = q.front();q.pop();for(int i = 0;i < E[front].size();i++){edge *tmp = &E[front][i];if(relax((*tmp).u,(*tmp).v,(*tmp).weight)){path[(*tmp).v] = front;cout<<front<<" ";if(visited[(*tmp).v] == 0){q.push((*tmp).v);visited[(*tmp).v] = 1;count[(*tmp).v]++;if(count[(*tmp).v] > vertexnum){while(!q.empty()){q.pop();}return false;}}}}visited[front] = 0;}return true;}void Print_Path(int x)  {      stack <int> s;      int w=x;      while(path[w] != -1)      {          s.push(w);          w=path[w];      }      cout<<"顶点 0 到顶点 "<<x<<" 的最短路径长度为:"<<dist[x]<<endl;      cout<<"所经过的路径为:0 ";      while(!s.empty())      {          cout<<s.top()<<" ";          s.pop();      }      cout<<endl;  } int main(int argc, char const *argv[]){getData();  int source = 0;dist[source] = 0;spfa(0);Print_Path(1);}


data:

0 1 6
0 4 7
1 4 8
1 2 5
2 1 -2
3 2 7
1 3 -4
4 3 9
4 2 -3
3 0 2

参考:http://www.cppblog.com/MiYu/archive/2010/10/23/131018.html

http://www.cnblogs.com/scau20110726/archive/2012/11/18/2776124.html

http://blog.csdn.net/kay_sprint/article/details/7295512

http://blog.csdn.net/oceanlight/article/details/7905584