单源最短路径

1、Bellman-Ford算法

该算法能解决单源最短路径问题,即使存在负权边的情况下。运行Bellman-Ford算法可以返回一个布尔值,如果为true,则说明图中不包含从源点可达的负权回路,算法将产生最短路径及其权值;如果为false,则说明图中包含从源点可达的负权回路,该问题无解。

 

View Code
 1 int d[50];
2 int p[50];
3
4 //initialize each distance of vertex to source, first source can't be reached
5 //p is the parent of vertex
6 void Init_SingleSource(const Graph* g,int source)
7 {
8 for(int i=0;i<g->vertex_num;++i)
9 {
10 d[i]=999;
11 p[i]=0;
12 }
13 d[source-1]=0;
14 }
15
16 //one step of relaxation
17 void Relaxation(int u,int v,int w)
18 {
19 if(d[u-1]+w<d[v-1])
20 {
21 d[v-1]=d[u-1]+w;
22 p[v-1]=u;
23 }
24 }

 

 

Bellman-Ford
 1 //First we initialize d & p,then we do relaxation on every edges, all |V|-1 times
2 //Last we check whether there is negative-weight circuit in the graph
3 bool Bellman_Ford(const Graph* g)
4 {
5 Init_SingleSource(g,1);
6 for(int i=1;i<=g->vertex_num-1;++i)
7 {
8 for(int j=0;j<g->edge_num;++j)
9 {
10 int u=g->edges[j].u;
11 int v=g->edges[j].v;
12 int w=g->edges[j].weight;
13 Relaxation(u,v,w);
14 }
15 }
16
17 for(int i=0;i<g->edge_num;++i)
18 {
19 int u=g->edges[i].u;
20 int v=g->edges[i].v;
21 int w=g->edges[i].weight;
22 if(d[v-1]>d[u-1]+w)
23 return false;
24 }
25 return true;
26 }

 

 2、有向无环图(DAG)中得单源最短路径

首先进行拓扑排序;

然后初始化d和p;

接着按照拓扑排序的顺序遍历每一个顶点,对每一个顶点的边进行松弛操作。

 

3、Dijkstra算法

该算法解决了有向图上带权的单源最短路径问题,但要求所有的边的权值非负。

首先自己实现最小优先队列

priority queue
 1 struct DijInfo
2 {
3 int dist;
4 int vertex;
5 };
6
7 DijInfo info[50];
8
9 void Maintain_Heap(DijInfo* arr,int i,int n)
10 {
11 while(2*(i+1)<=n)
12 {
13 int left=2*(i+1)-1;
14 int right;
15 if(2*(i+1)==n)
16 right=left;
17 else
18 right=2*(i+1);
19 int largest=i;
20 if(arr[left].dist>arr[largest].dist)
21 largest=left;
22 if(arr[right].dist>arr[largest].dist)
23 largest=right;
24 if(i==largest)
25 return;
26 else
27 {
28 int tmp=arr[largest].dist;
29 arr[largest].dist=arr[i].dist;
30 arr[i].dist=tmp;
31 tmp=arr[largest].vertex;
32 arr[largest].vertex=arr[i].vertex;
33 arr[i].vertex=tmp;
34 i=largest;
35 }
36 }
37 }
38
39 void Build_Heap(DijInfo* arr,int n)
40 {
41 int m=n/2-1;
42 for(;m>=0;--m)
43 Maintain_Heap(arr,m,n);
44 }
45
46 void Sort_Heap(DijInfo* arr,int n)
47 {
48 Build_Heap(arr,n);
49 for(int i=n-1;i>0;--i)
50 {
51 int tmp=arr[0].dist;
52 arr[0].dist=arr[i].dist;
53 arr[i].dist=tmp;
54 tmp=arr[0].vertex;
55 arr[0].vertex=arr[i].vertex;
56 arr[i].vertex=tmp;
57 Maintain_Heap(arr,0,i);
58 }
59 }

 

Dijkstra
 1 void Init_DijInfo(const Graph* g)
2 {
3 for(int i=0;i<g->vertex_num;++i)
4 {
5 info[i].vertex=i+1;
6 info[i].dist=d[i];
7 }
8 }
9
10 int search_info(int m,int n)
11 {
12 for(int i=0;i<n;++i)
13 if(info[i].vertex==m)
14 return i;
15 return n;
16 }
17
18 void Relaxation_Dij(int u,int v,int w,const Graph* g)
19 {
20 int i=search_info(u,g->vertex_num);
21 int j=search_info(v,g->vertex_num);
22 int d1=info[i].dist;
23 int d2=info[j].dist;
24 if(d1+w<d2)
25 info[j].dist=info[i].dist+w;
26 }
27
28 void Dijkstra(const Graph* g)
29 {
30 Init_SingleSource(g,1);
31 Init_DijInfo(g);
32 for(int i=0;i<g->vertex_num;++i)
33 {
34 Sort_Heap(info,g->vertex_num);
35 int u=info[i].vertex;
36 Edge* link=g->vertices[u-1].head;
37 while(link!=NULL)
38 {
39 int v=link->adj_vertex;
40 int w=link->weight;
41 Relaxation_Dij(u,v,w,g);
42 link=link->next;
43 }
44 }
45 }

 再给出一下伪代码

Dijkstra
1 DIJKSTRA(G,w,s)
2 INITIALIZE-SINGLE-SOURCE(G,s)
3 S=NULL
4 Q=V(G)
5 while(!Q.empty())
6 u=EXTRACT-MIN(Q)
7 S=S U {u}
8 for each vertex v which is ajacent vertex of u
9 RELAX(u,v,w)

 Dijkstra算法和广度优先搜索算法和Prim算法有相似之处。Dijkstra算法和广度优先搜索算法的相似之处在于,前者的集合S相当于后者的黑色顶点集合,正如集合S中的顶点有着最终的最短路径权值,广度优先搜索中的黑色顶点也有着正确的广度优先距离。Dijkstra算法与Prim算法的相似之处在于,两种算法均采用最小优先队列,来找出给定集合以外“最轻”的顶点,然后把该点加入到集合中,并相应调整该集合以外剩余顶点的权。

posted @ 2012-03-13 08:58  Cavia  阅读(776)  评论(0编辑  收藏  举报