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


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

    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≤5002le Nle 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

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

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

  • 相关阅读:
    【BUG】java.sql.SQLException: The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized or represents more than one time zone
    IntelliJ IDEA控制台输出中文乱码问题
    CMD命令
    MongoDB学习笔记
    MyBatis生成序列ID
    MongoDB配置问题
    正确处理下载文件时HTTP头的编码问题(Content-Disposition)
    SpringJPA主键生成采用自定义ID,自定义ID采用年月日时间格式
    Java根据经纬度算出附近正方形的四个角的经纬度
    gradle
  • 原文地址:https://www.cnblogs.com/yghjava/p/6853771.html
Copyright © 2020-2023  润新知