最短路径——Dijkstra

来源:互联网 发布:网易公开课优缺点知乎 编辑:程序博客网 时间:2024/05/14 19:42

迪杰斯特拉法最短路径:

其适用于权值为非负的图的单源最短路径, 建图可用邻接表,也可用邻接矩阵 。

非负的原因:归入S集合的节点的最短路径及其长度不再变更,如果边上的权值允许为负值,那么有可能出现当与S内某点(记为a)以负边相连的点(记为b)确定其最短路径时,它的最短路径长度加上这条负边的权值,结果小于a原先确定的最短路径长度,而此时a在Dijkstra算法下是无法更新的,由此便可能得不到正确的结果。

时间复杂度:使用邻接矩阵实现的dijkstra算法的复杂度是O(V²)。使用邻接表的话,更新最短距离只需要访问每条边一次即可,因此这部分的复杂度是O(E).但是每次要枚举所有的顶点来查找下一个使用的顶点,因此最终复杂度还是O(V²)。在|E|比较小时,大部分的时间都花在了查找下一个使用的顶点上,因此需要使用堆或者优先级队列进行优化。

需要优化的是数值的插入(更新)和取出最小值两个操作,因此使用堆就可以了。把每个顶点当前的最短距离用堆来维护,在更新最短距离时,把对应的元素往根的方向移动以满足堆的性质。而每次从堆中取出的最小值就是下一次要用的顶点。这样堆中的元素共有O(V)个,更新和取出的操作有O(E)次,因此整个算法的复杂度是O(ElogV)。(参考:http://blog.csdn.net/tlonline/article/details/47398403)

O(n^2)代码:

#include <stdio.h>#include <vector>#define INF 0xffffff#define N 220using namespace std;struct Road{int next;int len;};int CityNum, RoadNum;vector<Road>City[N];// 保存i城市所有对外的路径 int dis[N];// 保存最短距离 bool vis[N];void Init(){// 初始化 for(int i = 0; i <= CityNum; i ++){City[i].clear();dis[i] = INF;// 初始 dis 数组初始化位最大,后不断更新为最短距离 vis[i] = 0;}}void Dijkstra(int choose){while(!vis[choose]){vis[choose] = 1;// 标记当前城市 for(int i = 0; i < City[choose].size(); i ++){// 遍历该城市对外的所有路径 int next = City[choose].at(i).next;int len = City[choose].at(i).len;if(dis[next] > dis[choose] + len){// 更新最短路 dis[next] = dis[choose] + len;}}int Min = INF;for(int i = 0; i < CityNum; i ++){// 选取距离最近的作为下一轮的出发点 if(!vis[i] && Min > dis[i]){Min = dis[i];choose = i;}}}}int main(){Road nw;int start, end, len;while(scanf("%d%d", &CityNum, &RoadNum) != EOF){Init();// 初始化for(int i = 0; i < RoadNum; i ++){// 建无向图 scanf("%d%d%d", &start, &end, &len);nw.next = end;nw.len = len;City[start].push_back(nw);nw.next = start;City[end].push_back(nw);}scanf("%d%d", &start, &end);dis[start]=0;Dijkstra(start);if(dis[end] == INF){printf("-1\n");}else{printf("%d\n", dis[end]);}}}

优化后代码:

void Dijkstra(int choose){      priority_queue<node> Q;      node p, q;      p.x = choose;      p.dis = 0;      Q.push(p);      while(!Q.empty()){          p = Q.top();          Q.pop(); choose = p.x;         if(vis[choose])continue;         vis[choose] = true;        for(int i = 0; i < City[choose].size(); i ++){             int next = City[choose].at(i).next;              int len = City[choose].at(i).len;              if(dis[next] > dis[choose] + len){                dis[next] = dis[choose] + len;q.x = next;q.dis = dis[next];Q.push(q);              }          }      }  } 

 

0 0