本博客的代码的思想和图片参考:好大学慕课浙江大学陈越老师、何钦铭老师的《数据结构》
Dijkstra 算法
令S={源点s + 已经确定了最短路径的顶点v i }
对任一未收录的顶点v,定义dist[v]为s到v的最
短路径长度,但该路径仅经过S中的顶点。即路径
{s(v i S)v}的最小长度
若路径是按照递增(非递减)的顺序生成的,则
真正的最短路必须只经过S中的顶点(为什么?)
每次从未收录的顶点中选一个dist最小的收录(贪心)
增加一个v进入S,可能影响另外一个w的dist值!
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 }
测试数据:
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≤5002le Nle 5002≤N≤500)是城市的个数,顺便假设城市的编号为0~(N−1N-1N−1);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 }
但是这个代码也不能通过所以的测试,系统设置价格和最短路径都相同的路径,好像要列出所以的路径,但是我为了赶课程进度,就没有深究了
如果你找到了问题,可以在在评论区回复我。谢谢!