单源点有权图的最短路径算法

本博客的代码的思想和图片参考:好大学慕课浙江大学陈越老师、何钦铭老师的《数据结构》

Dijkstra 算法

S={源点s + 已经确定了最短路径的顶点v i }

对任一未收录的顶点v,定义dist[v]sv的最

短路径长度,但该路径仅经过S中的顶点。即路径

{s(v i S)v}的最小长度

若路径是按照递增(非递减)的顺序生成的,

真正的最短路必须只经过S中的顶点(为什么?)

每次从未收录的顶点中选一个dist最小的收录(贪心)

增加一个v进入S,可能影响另外一个wdist!

dist[w] = min{dist[w], dist[v] + <v,w>的权重}



伪代码描述:

void Dijkstra( Vertex s )

{ while (1) {

V = 未收录顶点中dist最小者;

if ( 这样的V不存在 )

break;

collected[V] = true;

for ( V 的每个邻接点 W )

if ( collected[W] == false )

if ( dist[V]+E <V,W> < dist[W] ) {

dist[W] = dist[V] + E <V,W> ;

path[W] = V;

}

}

} /* 不能解决有负边的情况 */



算法复杂度分析:

方法1:直接扫描所有未收录顶点 – O( |V| )

T = O( |V| 2 + |E| )

对于稠密图效果好

方法2:dist存在最小堆中 – O( log|V| )

更新dist[w]的值 – O( log|V| )

T = O( |V| log|V| + |E| log|V| ) = O( |E| log|V| )

 

  1 /*
  2  * dijkstra.c
  3  *
  4  *  Created on: 2017年5月14日
  5  *      Author: ygh
  6  */
  7 
  8 #include <stdio.h>
  9 #include <stdlib.h>
 10 
 11 #define MAX_VERTEX_NUM 100 /*define the max number of the vertex*/
 12 #define INFINITY 65535     /*define double byte no negitive integer max number is 65535*/
 13 #define ERROR -1
 14 
 15 typedef int vertex; /*define the data type of the vertex*/
 16 typedef int weightType; /*define the data type of the weight*/
 17 typedef char dataType; /*define the data type of the vertex value*/
 18 
 19 /*define the data structure of the Edge*/
 20 typedef struct eNode *ptrToENode;
 21 typedef struct eNode {
 22     vertex v1, v2; /*two vertex between the edge <v1,v2>*/
 23     weightType weight; /*the value of the edge's weigth */
 24 };
 25 typedef ptrToENode edge;
 26 
 27 /*define the data structure of the graph*/
 28 typedef struct gNode *ptrToGNode;
 29 typedef struct gNode {
 30     int vertex_number; /*the number of the vertex*/
 31     int edge_nunber; /*the number of the edge*/
 32     weightType g[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; /*define the adjacent matrix of graph*/
 33     dataType data[MAX_VERTEX_NUM]; /*define the dataType array to store the value of vertex*/
 34 };
 35 typedef ptrToGNode adjacentMatrixGraph; /*a graph show by adjacent matrix*/
 36 
 37 /*
 38  create a graph given the vertex number.
 39  @param vertexNum The verter number of the graph
 40  @return a graph with vertex but no any egdgs
 41  */
 42 adjacentMatrixGraph createGraph(int vertexNum) {
 43     vertex v, w;
 44     adjacentMatrixGraph graph;
 45     graph = (adjacentMatrixGraph) malloc(sizeof(struct gNode));
 46     graph->vertex_number = vertexNum;
 47     graph->edge_nunber = 0;
 48     /*initialize the adjacent matrix*/
 49     for (v = 0; v < graph->vertex_number; v++) {
 50         for (w = 0; w < graph->vertex_number; w++) {
 51             graph->g[v][w] = INFINITY;
 52         }
 53     }
 54 
 55     return graph;
 56 }
 57 
 58 /*
 59  insert a edge to graph.We will distinct oriented graph and undirected graph
 60  @param graph The graph you want to insert edge
 61  @param e The edge you want to insert the graph
 62  @param isOriented Whether the graph is oriented graph.If the graph is oriented
 63  we will set adjacent matrix [n][m]=[m][n]=edge's weight,else we only set
 64  the adjacent matrix [n][m]=edge's weight
 65  */
 66 void inserEdge(adjacentMatrixGraph graph, edge e, int isOriented) {
 67     graph->g[e->v1][e->v2] = e->weight;
 68     if (!isOriented) {
 69         graph->g[e->v2][e->v1] = e->weight;
 70     }
 71 }
 72 
 73 /*
 74  construct a graph according user's input
 75 
 76  @return a graph has been filled good
 77  */
 78 adjacentMatrixGraph buildGraph(int isOrdered) {
 79     adjacentMatrixGraph graph;
 80     edge e;
 81     vertex i;
 82     int vertex_num;
 83     scanf("%d", &vertex_num);
 84     graph = createGraph(vertex_num);
 85     scanf("%d", &(graph->edge_nunber));
 86     if (graph->edge_nunber) {
 87         e = (edge) malloc(sizeof(struct eNode));
 88         for (i = 0; i < graph->edge_nunber; i++) {
 89             scanf("%d %d %d", &e->v1, &e->v2, &e->weight);
 90             e->v1--;
 91             e->v2--;
 92             inserEdge(graph, e, isOrdered);
 93         }
 94     }
 95     return graph;
 96 
 97 }
 98 
 99 /*
100  * Find the the index of point in the graph whose dist is minimal and has not been
101  * accessed.
102  * @param graph A graph which use adjacent matrix to store
103  * @param dist A integer array to store the length from source to destination, it will be initialize with 65535 at first
104  * @param collection A integer array to show whether the point has been accessed
105  *         0 indicates the point has not been accessed,`1 indicates the point has been accessed
106  *         the index in collection is same as the graph
107  */
108 vertex findMinDist(adjacentMatrixGraph graph, int *dist, int *collection) {
109     vertex minVertex, v;
110     int minDist = INFINITY;
111     /*
112      * Find the minimal dist
113      */
114     for (v = 0; v < graph->vertex_number; v++) {
115         if (dist[v] < minDist && collection[v] == 0) {
116             minDist = dist[v];
117             minVertex = v;
118         }
119     }
120 
121     if (minDist < INFINITY) {
122         return minVertex;
123     } else {
124         return ERROR;
125     }
126 }
127 
128 /*
129  * Find the shortest path from source to every point in graph with weight
130  *@param graph A graph which use adjacent matrix to store
131  *@param dist A integer array to store the length from source to destination, it will be initialize with 65535 at first
132  *@param path A integer to store the index of last vertex which is shortest to pass current point,it will be initialize -1
133  *@return 1 indicate the algorithms is correct calculate the result,0 indicates there is negative edge in the graph,a error happened
134  */
135 int dijkstar(adjacentMatrixGraph graph, int *dist, int *path, vertex startPoint) {
136     int collection[graph->vertex_number];
137     vertex v, w;
138     for (v = 0; v < graph->vertex_number; v++) {
139         dist[v] = graph->g[startPoint][v];
140         if (dist[v] < INFINITY) {
141             path[v] = startPoint;
142         } else {
143             path[v] = -1;
144             collection[v] = 0;
145         }
146     }
147     collection[startPoint] = 1;
148     dist[startPoint] = 0;
149     while (1) {
150         v = findMinDist(graph, dist, collection);
151         if (v == ERROR) {
152             break;
153         }
154         collection[v] = 1;
155         for (w = 0; w < graph->vertex_number; w++) {
156             if (collection[w] == 0 && graph->g[v][w] < INFINITY) {
157                 /*
158                  * If a edge weight is a negative,Dijkstra will not to solve it,return 0
159                  */
160                 if (graph->g[v][w]<0) {
161                     return 0;
162                 }
163                 /*
164                  * If v make dist[w] get smaller,updata it
165                  */
166                 if (dist[v] + graph->g[v][w] < dist[w]) {
167                     dist[w] = dist[v] + graph->g[v][w];
168                     path[w] = v;
169                 }
170             }
171         }
172     }
173     return 1;
174 }
175 
176 /*============================define a stack to print result=============*/
177 typedef int stackElement;
178 typedef struct node3 {
179     stackElement element;
180     struct node3 *next;
181 } sta, *pStack;
182 
183 pStack createEmptyStack() {
184     pStack stack;
185     stack = (pStack) malloc(sizeof(sta));
186     if (stack) {
187         stack->next = NULL;
188     }
189     return stack;
190 }
191 
192 int isEmpty(pStack stack) {
193     if (stack->next == NULL) {
194         return 1;
195     } else {
196         return 0;
197     }
198 }
199 
200 void push(pStack stack, stackElement element) {
201     pStack node = (pStack) malloc(sizeof(sta));
202     node->element = element;
203     node->next = stack->next;
204     stack->next = node;
205 }
206 
207 stackElement pop(pStack stack) {
208     stackElement element;
209     pStack topHead;
210     if (isEmpty(stack)) {
211         printf("the stack is empty,can not pop");
212         return -65536;
213     } else {
214         topHead = stack->next;
215         stack->next = topHead->next;
216         element = topHead->element;
217         free(topHead);
218         return element;
219     }
220 }
221 
222 void findPath(int *path, int length, int destination) {
223     pStack stack = createEmptyStack();
224     vertex v;
225     int index = destination;
226     push(stack, index);
227     while (v != -1) {
228         v = path[index];
229         push(stack, v);
230         index = v;
231     }
232 
233     pop(stack);
234     while (!isEmpty(stack)) {
235         stackElement element = pop(stack);
236         printf("%d ", element + 1);
237     }
238 }
239 
240 /*
241  * Fill a array with value
242  * @param arr The array need to be filled
243  * @param length The length of the array
244  * @param filledValue The value the array will be filled
245  */
246 void fullArray(int *arr, int length, int filledValue) {
247     int i;
248     for (i = 0; i < length; i++) {
249         arr[i] = filledValue;
250     }
251 }
252 int main() {
253     adjacentMatrixGraph graph = buildGraph(1);
254     int dist[graph->vertex_number];
255     int path[graph->vertex_number];
256     dijkstar(graph, dist, path, 0);
257     findPath(path, graph->edge_nunber, 5);
258     return 0;
259 }
Dijkstra

 

测试数据:

a data of graph:

7 12
1 2 2
1 4 1
2 5 10
2 4 3
3 1 4
3 6 5
4 3 2
4 6 8
4 7 4
4 5 2
5 7 6
7 6 1

from 1 to 6 shortest path
1 4 7 6

 

下面列举一道题目:

有了一张自驾旅游路线图,你会知道城市间的高速公路长度、以及该公路要收取的过路费。现在需要你写一个程序,帮助前来咨询的游客找一条出发地和目的地之间的最短路径。如果有若干条路径都是最短的,那么需要输出最便宜的一条路径。

输入格式:

输入说明:输入数据的第1行给出4个正整数NNN、MMM、SSS、DDD,其中NNN(2≤N≤5002\le N\le 5002N500)是城市的个数,顺便假设城市的编号为0~(N−1N-1N1);MMM是高速公路的条数;SSS是出发地的城市编号;DDD是目的地的城市编号。随后的MMM行中,每行给出一条高速公路的信息,分别是:城市1、城市2、高速公路长度、收费额,中间用空格分开,数字均为整数且不超过500。输入保证解的存在。

输出格式:

在一行里输出路径的长度和收费总额,数字间以空格分隔,输出结尾不能有多余空格。

输入样例:

4 5 0 3
0 1 1 20
1 3 2 30
0 3 4 10
0 2 2 20
2 3 1 20

输出样例:

3 40

 

算法思想:其实很简单,我们只需要在Dijkstra算法的基础上,除了吧路径的长度(权重)作为最短路径以外,还需要把价格按照路径的相同方法进行

更新和记录。当路径不等时,我们优先考虑路径,并根据路径的长短里记录上一个节点的角标。如果路径相等,我们需要根据价格来判断上一个节点的

角标。这样就可以实现这道题目了。在插入城市节点的时候,注意是无向图,不然代码会不通过的。下面是具体的代码

  1 /*
  2  * travelPlan.c
  3  *
  4  *  Created on: 2017年5月14日
  5  *      Author: ygh
  6  */
  7 #include <stdio.h>
  8 #include <stdlib.h>
  9 
 10 #define MAX_VERTEX_NUM 500 /*define the max number of the vertex*/
 11 #define INFINITY 65535     /*define double byte no negitive integer max number is 65535*/
 12 #define ERROR -1
 13 
 14 typedef int vertex; /*define the data type of the vertex*/
 15 typedef int weightType; /*define the data type of the weight*/
 16 typedef char dataType; /*define the data type of the vertex value*/
 17 typedef int priceType;
 18 
 19 /*define the data structure of the Edge*/
 20 typedef struct eNode *ptrToENode;
 21 typedef struct eNode {
 22     vertex v1, v2; /*two vertex between the edge <v1,v2>*/
 23     weightType weight; /*the value of the edge's weight */
 24     priceType price; /*The value of price of the price*/
 25 };
 26 typedef ptrToENode edge;
 27 
 28 /*define the data structure of the graph*/
 29 typedef struct gNode *ptrToGNode;
 30 typedef struct gNode {
 31     vertex source; /*The index of the source*/
 32     vertex destination; /*The index of the destination*/
 33     int vertex_number; /*the number of the vertex*/
 34     int edge_nunber; /*the number of the edge*/
 35     weightType g[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; /*define the adjacent matrix weight of graph*/
 36     priceType p[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; /*define the adjacent matrix price of graph*/
 37     dataType data[MAX_VERTEX_NUM]; /*define the dataType array to store the value of vertex*/
 38 };
 39 typedef ptrToGNode adjacentMatrixGraph; /*a graph show by adjacent matrix*/
 40 
 41 /*
 42  create a graph given the vertex number.
 43  @param vertexNum The verter number of the graph
 44  @return a graph with vertex but no any egdgs
 45  */
 46 adjacentMatrixGraph createGraph(int vertexNum) {
 47     vertex v, w;
 48     adjacentMatrixGraph graph;
 49     graph = (adjacentMatrixGraph) malloc(sizeof(struct gNode));
 50     graph->vertex_number = vertexNum;
 51     graph->edge_nunber = 0;
 52     /*initialize the adjacent matrix*/
 53     for (v = 0; v < graph->vertex_number; v++) {
 54         for (w = 0; w < graph->vertex_number; w++) {
 55             graph->g[v][w] = INFINITY;
 56             graph->p[v][w] = INFINITY;
 57         }
 58     }
 59 
 60     return graph;
 61 }
 62 
 63 /*
 64  insert a edge to graph.We will distinct oriented graph and undirected graph
 65  @param graph The graph you want to insert edge
 66  @param e The edge you want to insert the graph
 67  @param isOriented Whether the graph is oriented graph.If the graph is oriented
 68  we will set adjacent matrix [n][m]=[m][n]=edge's weight,else we only set
 69  the adjacent matrix [n][m]=edge's weight
 70  */
 71 void inserEdge(adjacentMatrixGraph graph, edge e, int isOriented) {
 72     graph->g[e->v1][e->v2] = e->weight;
 73     graph->p[e->v1][e->v2] = e->price;
 74     if (!isOriented) {
 75         graph->g[e->v2][e->v1] = e->weight;
 76         graph->p[e->v2][e->v1] = e->price;
 77     }
 78 }
 79 
 80 /*
 81  construct a graph according user's input
 82 
 83  @return a graph has been filled good
 84  */
 85 adjacentMatrixGraph buildGraph(int isOrdered) {
 86     adjacentMatrixGraph graph;
 87     edge e;
 88     vertex i;
 89     vertex source, destination;
 90     int vertex_num;
 91     scanf("%d", &vertex_num);
 92     graph = createGraph(vertex_num);
 93     scanf("%d", &(graph->edge_nunber));
 94     scanf("%d %d", &source, &destination);
 95     graph->source = source;
 96     graph->destination = destination;
 97     if (graph->edge_nunber) {
 98         e = (edge) malloc(sizeof(struct eNode));
 99         for (i = 0; i < graph->edge_nunber; i++) {
100             scanf("%d %d %d %d", &e->v1, &e->v2, &e->weight, &e->price);
101             inserEdge(graph, e, isOrdered);
102         }
103     }
104     return graph;
105 
106 }
107 
108 /*
109  * Find the the index of point in the graph whose dist is minimal and has not been
110  * accessed.
111  * @param graph A graph which use adjacent matrix to store
112  * @param dist A integer array to store the length from source to destination, it will be initialize with 65535 at first
113  * @param collection A integer array to show whether the point has been accessed
114  *         0 indicates the point has not been accessed,`1 indicates the point has been accessed
115  *         the index in collection is same as the graph
116  */
117 vertex findMinDist(adjacentMatrixGraph graph, int *dist, int *collection) {
118     vertex minVertex, v;
119     int minDist = INFINITY;
120     /*
121      * Find the minimal dist
122      */
123     for (v = 0; v < graph->vertex_number; v++) {
124         if (dist[v] < minDist && collection[v] == 0) {
125             minDist = dist[v];
126             minVertex = v;
127         }
128     }
129 
130     if (minDist < INFINITY) {
131         return minVertex;
132     } else {
133         return ERROR;
134     }
135 }
136 
137 /*
138  * Find the shortest path from source to every point in graph with weight
139  *@param graph A graph which use adjacent matrix to store
140  *@param dist A integer array to store the length from source to destination, it will be initialize with 65535 at first
141  *@param path A integer to store the index of last vertex which is shortest to pass current point,it will be initialize -1
142  *@return 1 indicate the algorithms is correct calculate the result,0 indicates there is negative edge in the graph,a error happened
143  */
144 int dijkstar(adjacentMatrixGraph graph, int *dist, int *path, int *totalPrice,
145         vertex startPoint) {
146     int collection[graph->vertex_number];
147     vertex v, w;
148     for (v = 0; v < graph->vertex_number; v++) {
149         dist[v] = graph->g[startPoint][v];
150         totalPrice[v] = graph->p[startPoint][v];
151         if (dist[v] < INFINITY) {
152             path[v] = startPoint;
153         } else {
154             path[v] = -1;
155             collection[v] = 0;
156         }
157     }
158     collection[startPoint] = 1;
159     dist[startPoint] = 0;
160     totalPrice[startPoint] = 0;
161     while (1) {
162         v = findMinDist(graph, dist, collection);
163         if (v == ERROR) {
164             break;
165         }
166         collection[v] = 1;
167         for (w = 0; w < graph->vertex_number; w++) {
168             if (collection[w] == 0 && graph->g[v][w] < INFINITY) {
169                 /*
170                  * If a edge weight is a negative,Dijkstra will not to solve it,return 0
171                  */
172                 if (graph->g[v][w] < 0) {
173                     return 0;
174                 }
175                 /*
176                  * If v make dist[w] get smaller,updata it
177                  */
178                 if (dist[v] + graph->g[v][w] < dist[w]) {
179                     dist[w] = dist[v] + graph->g[v][w];
180                     totalPrice[w] = totalPrice[v] + graph->p[v][w];
181                     path[w] = v;
182                 } else if ((dist[v] + graph->g[v][w] == dist[w])
183                         && (totalPrice[w] > totalPrice[v] + graph->p[v][w])) {
184                     totalPrice[w] = totalPrice[v] + graph->p[v][w];
185                     path[w] = v;
186                 }
187             }
188         }
189     }
190     return 1;
191 }
192 
193 /*============================define a stack to print result=============*/
194 typedef int stackElement;
195 typedef struct node3 {
196     stackElement element;
197     struct node3 *next;
198 } sta, *pStack;
199 
200 pStack createEmptyStack() {
201     pStack stack;
202     stack = (pStack) malloc(sizeof(sta));
203     if (stack) {
204         stack->next = NULL;
205     }
206     return stack;
207 }
208 
209 int isEmpty(pStack stack) {
210     if (stack->next == NULL) {
211         return 1;
212     } else {
213         return 0;
214     }
215 }
216 
217 void push(pStack stack, stackElement element) {
218     pStack node = (pStack) malloc(sizeof(sta));
219     node->element = element;
220     node->next = stack->next;
221     stack->next = node;
222 }
223 
224 stackElement pop(pStack stack) {
225     stackElement element;
226     pStack topHead;
227     if (isEmpty(stack)) {
228         printf("the stack is empty,can not pop");
229         return -65536;
230     } else {
231         topHead = stack->next;
232         stack->next = topHead->next;
233         element = topHead->element;
234         free(topHead);
235         return element;
236     }
237 }
238 
239 void calculateDistanceAndFee(adjacentMatrixGraph graph, int *path, int length,
240         int destination) {
241     pStack stack = createEmptyStack();
242     vertex v;
243     int index = destination;
244     int totalDistace = 0;
245     int totalPrice = 0;
246     int arr[graph->vertex_number];
247     int counter = 0, i;
248     push(stack, index);
249     while (v != -1) {
250         v = path[index];
251         push(stack, v);
252         index = v;
253     }
254 
255     pop(stack);
256     while (!isEmpty(stack)) {
257         stackElement element = pop(stack);
258         arr[counter++] = element;
259     }
260 
261     for (i = 1; i < counter; i++) {
262         totalDistace = totalDistace + graph->g[arr[i - 1]][arr[i]];
263         totalPrice = totalPrice + graph->p[arr[i - 1]][arr[i]];
264     }
265 
266     printf("%d %d", totalDistace, totalPrice);
267 }
268 
269 /*
270  * Fill a array with value
271  * @param arr The array need to be filled
272  * @param length The length of the array
273  * @param filledValue The value the array will be filled
274  */
275 void fullArray(int *arr, int length, int filledValue) {
276     int i;
277     for (i = 0; i < length; i++) {
278         arr[i] = filledValue;
279     }
280 }
281 int main() {
282     /*
283      * This is a no-direct graph
284      */
285     adjacentMatrixGraph graph = buildGraph(0);
286     int dist[graph->vertex_number];
287     int path[graph->vertex_number];
288     int totalPrice[graph->vertex_number];
289     dijkstar(graph, dist, path, totalPrice, 0);
290     calculateDistanceAndFee(graph, path, graph->edge_nunber,
291             graph->destination);
292     return 0;
293 }
Travel-Plan

但是这个代码也不能通过所以的测试,系统设置价格和最短路径都相同的路径,好像要列出所以的路径,但是我为了赶课程进度,就没有深究了

如果你找到了问题,可以在在评论区回复我。谢谢!

 

posted @ 2017-05-14 20:59  浪漫逆风  阅读(569)  评论(0编辑  收藏  举报