最短路问题是图论中最基础的问题,在面试题中出现的次数也很多,很多类似最少步数等问题都能转化到最短路问题,这篇文章介绍单源最短路问题的两种算法。单源最短路问题是固定一个起点,求它到其他所有点的最短路问题,如果只求两个固定点之间的最短路,看起来要简单很多,但其实复杂度是一样的,所以我们广泛的讨论单源最短路问题。
struct edge{ int from, to , cost} //边的结构体:顶点from到顶点to的权值cost edge es[MAX_E]; //边的数组 int d[MAX_V]; //距离的数组 int V,E; //顶点数和边数 void shortest_path(int s){ for (int i=0;i<V;i++) d[i]=INF; d[s]=0; while(true) bool update=false; for(int i=0;i<E;i++) edge e=es[i]; if(d[e.from]!=INF&&d[e.to]>d[e.form]+e.cost){ //从已经想连的顶点中找到满足条件的 d[e.to]=d[e.from]+e.cost; update=true; } } if(!update) break; //所有顶点都更新过后,结束 } }复杂度:while最多循环|V|-1次,所以是O(|V|*|E|)。
int cost[MAX_V][MAX_E] int d[MAX_V]; bool used[MAX_V]; int V; void dijkstra(int s){ fill(d,d+V,INF); fill(used,used+V,false); d[s]=0; while(true){ int v=-1; for(int u=0;u<V;u++){ //从未使用的顶点中选择一个距离最小的顶点(while的第一次循环选择的是点s) if(!used[u]&&(v==-1||d[u]<d[v])) v=u; } if (v==-1) break; used[v]=true; for(int u=0;u<V;u++){ d[u]=min(d[u],d[v]+cost[v][u]); //更新和确定的点相连的点的距离 } } }这种写法的复杂度是O(|V|^2),代码中大部分时间花在查找下一个使用的顶点上,我们可以使用好的数据结构保护好这个顶点,在有数值插入的情况下要得到集合中的最小值,那么最好的数据结构是堆,堆中元素有O(|V|)个,需要更新O(|E|)次,所以复杂度为O(|E|log|V|)。
struct edge{int to, cost} typedef pair<int ,int> P; //first是最短距离,second是顶点编号 int d[MAX_V]; vector<edge> G[MAX_V];//邻接表 int V; void dijkstra(int s){ priority_queue<P,vector<p>,greater<p>> que; //greater表示从小到大 fill(d,d+V,INF); d[s]=0; que.push(P(0,s)); while(!que.empty()){ P p=que.top(); //取出确定点 que.pop(); int v=p.second; if(d[v]<p.first) continue; for(int i=0;i<G[v].size();i++) { edge e=G[v][i]; //边为从点v到点i if(d[e.to]>d[v]+e.cost;){ d[e.to]=d[v]+e.cost; que.push(P(d[e.to],e.to)); //把更新的距离和点放进堆 } } } }如果使用斐波那契堆,性能还能提高,就是有点复杂。
原文地址:http://blog.csdn.net/ji_zailushang/article/details/24670881