Reprint: The smallest spanning tree and shortest path of graphs

Source: Internet
Author: User

Reproduced in the full text of the http://blog.csdn.net/spaceyqy/article/details/39024675 if the author thinks wrong, will be deleted

Overview


The minimum spanning tree of graphs is not much correlated with the shortest path, but the idea of greedy algorithm is applied to some extent, but the difference between them is obvious.

difference:

The minimum spanning tree can ensure that the first tree (for n vertices of the graph only n-1 edge), and then ensure that any two vertices can be reached, and again ensure that the sum of the tree Benquan value is the smallest, but can not guarantee that any two points between the shortest path;

The shortest path guarantees the smallest path from the source point s to the target location D (the direction diagram does not require the endpoint to start) and does not guarantee that any two vertices can be reached;

A graph if there is a negative weight ring ... Path length can be infinitely small, because you can continue to go this ring lower weight, and the minimum spanning tree is limited, it is not how you go to the problem, but to generate a 22 can reach the minimum weight and the problem of the tree.

The minimum spanning tree is the minimum cost to traverse all vertices in the entire graph, with all weights and minimum values. The shortest path is only to ensure the starting point to the end of the path and the smallest, not necessarily through all vertices;

The minimum spanning tree is the path cost and minimum to a group of points (all points), is a n-1 tree, and the shortest path is the shortest path from one point to another.


minimum Spanning Tree


The spanning tree of a connected graph is a minimal connected subgraph, which contains all the vertices of the graph, but only enough to form the n-1 of a tree. Then we refer to the minimum spanning tree of constructing a connected network as the least cost spanning tree.

To find the minimum spanning tree of connected networks, there are two classical algorithms, Primm algorithm and Kruskal algorithm. The following two algorithms are described separately.


First, Primm (Prim) algorithm


Primm algorithm, an algorithm in graph theory, can search for a minimum spanning tree in a weighted connected graph. That is, the tree in which the edge subset is searched by this algorithm includes not only all vertices in the connected graph, but also the sum of the weights of all the edges is the smallest.


1.1 Algorithm Description


Starting with a single vertex, the Primm algorithm progressively expands the number of vertices in the tree by the following steps until all vertices of the connected graph are spread.
(1) Input: A weighted connected graph in which the vertex set is V and the edge set is E;
(2) Initialization: Vnew = {x}, where x is any node in the Set V (starting point), enew = {};
(3) Repeat the following operation until Vnew = V:
Select the Edge (U, v) with the smallest weighted value in set E, where U is the element in the set vnew, and V is not (if there are multiple edges with the same weights that satisfy the foregoing conditions, one can be chosen arbitrarily);
Adding V to the Set vnew, adding (U, v) to the set enew;
(4) Output: Use Set vnew and enew to describe the resulting minimum spanning tree.


1.2 cases showed




1.3 Primm Algorithm Implementation

    <strong>//prim algorithm minimum spanning tree void Minispantree_prime (Graph g) {int min, I, J, K;         int Adjvex[maxvex];        Save related vertex subscript int Lowcost[maxvex];             To save the weights of the relative vertex lowcost[0] = 0;              Initialize the first weight value is 0, namely V0 joins the spanning tree adjvex[0] = 0; Initializes the first vertex subscript 0 for (i = 1; i < g.numvertexes i++) {//loop all Vertex low except subscript 0)   Cost[i] = G.arc[0][i];              Storing the weights of the v0 vertices and their edges in an array adjvex[i] = 0;             Initialization is v0} for (i = 1; i < g.numvertexes; i++) {min = INFINITY;  
            Initialize the minimum weight to infinity j = 1;  
            k = 0; while (J < g.numvertexes)//Loop full vertex {//If the weight value is not 0, and the weight value is less than min if (lowcost[j)       != 0 && Lowcost[j] < min) {min = lowcost[j];               Let the current weight become the minimum value k = j;   Deposit the subscript of the current minimum value in K} j + +;                 printf ("(%d,%d)", Adjvex[k], k);//Print the minimum edge of the right value in the current vertex edge lowcost[k] = 0;  
                Sets the weight value of the current vertex to 0, indicating that the vertex has completed the task for (j = 1; j < G.numvertexes; J +)/loop all vertices { if (Lowcost[j]!= 0 && g.arc[k][j] < Lowcost[j] {//If the vertex values of the vertices are subscript k  
                    The spanning tree weights lowcost[j] = g.arc[k][j] are smaller than those before these vertices were not added;         ADJVEX[J] = k;  
    The vertex labeled K is saved to Adjvex}} printf ("\ n");   } </strong>

From the realization of the code, the time complexity of the prim algorithm implemented by adjacency Matrix is O (n^2).


Two, Kruskal (Kruskal) algorithm

The prim algorithm takes a vertex as the starting point, and gradually find the edge of the minimum weight on each vertex to construct the minimum spanning tree. The same idea, we can also directly on the edge to build a tree is also very natural ideas, but the construction to consider whether it will form a loop. At this point, we use the array structure of the edge set in the storage structure of the graph. Here is the definition code for the array structure of the edge edge set:

typedef struct  
  {  
      int begin;  
      int end;  
     int weight;  
 } Edge;

We can use the program to convert the adjacency matrix into an array of edge sets, and to sort their weights from small to large. As shown in the following figure.

So the Kruskal algorithm code is as follows, the left number is line number. Where Maxedge is the maximum value of the number of edges, Maxvex is the maximum number of vertices. The specific code is shown below.

    Find the tail of the line vertex int found (int *parent, int f) {while (Parent[f] > 0) {f =  
        PARENT[F];  
    } return F;  
        The//Kruskal algorithm implements void Minispantree_kruskal (Graph g) {int i, n, M;    Edge Edges[maxedge];     Defines an array of edge sets int Parent[maxvex];  
        Define an array to determine whether the edges and edges form a ring//here to convert the adjacency matrix to an array of edges and to sort by weight from small to large (g, edges);  for (i = 0; i < g.numvertexes i++) {parent[i] = 0; Initialize array value 0} for (i = 0; i < g.numedges; i++)//loop each edge {n  
            = Find (parent, edges[i].begin);  
            M = Find (parent, edges[i].end);  if (n!= m)//if n differs from M, this side does not form a loop with the existing spanning tree {parent[n] = m; Place the end vertex of this edge into parent in subscript start//indicates that this vertex has been printf in the Spanning Tree collection ("(%d,%d)%d", EdGes[i].begin, Edges[i].end, edges[i].weight);  
    printf ("\ n");   }

The Find function of the Kruskal algorithm is determined by the number of edges E, the time complexity is O (Loge), and the outside has a for loop e time, so the Kruskal algorithm's time complexity is O (eloge). This does not include an array of adjacency matrices converted to edge sets.


Summary


Compared with two algorithms, the CROUSLE algorithm is mainly for the edge of the expansion, the number of days is very high efficiency, so the sparse map has a great advantage, and Primm algorithm for dense graph, that is, the number of edges is very much better.

Shortest Path


For a network diagram, the shortest path is the sum of the edges and the least path that passes between the vertices, and we say that the first vertex on the path is the source and the second vertex is the end point. Instead of a net map, it can be understood that all edges have a net weight of 1.


First, Dijkstra (Dijkstra) algorithm


The Dijkstra algorithm is to extend the starting point as the center to the outer layer until the end is extended, and the shortest path algorithm is generated in order of increasing path length. Dijkstra algorithm can get the optimal solution of shortest path, but it is inefficient because it traverses many nodes of computation.

1. Algorithm idea
so that G = (v,e) is a weighted direction graph, the vertex set V in the graph is divided into two groups, the first group is the vertex set S of the shortest path that has been obtained (only the source node in the initial s), each time a shortest path is obtained, the corresponding vertex is added to the set S, until all vertices are added to s. The second group is the vertex set U of the shortest path that is not determined. During the join process, the shortest path length of the total remains from the source node V to S is less than the shortest path length from the source node V to any vertex in U.

2. Algorithm steps
(1) When initializing, s only contains the source node;
(2) Select a vertex k with the smallest distance v from U to join S (the selected distance is the shortest path length of V to K);
(3) with K as the middle point of the new consideration, modify the distance of each vertex in U, if the distance from the source node V to the vertex u (through vertex K) is shorter than the original distance (not through the vertex K), modify the distance value of the vertex u, and the distance value is the distance of vertex K plus k to U.
(4) Repeat steps (2) and (3) until all vertices are contained in S.


Specific legend and algorithm execution steps: (starting from a, to the shortest path of each node).

    /* Dijkstra algorithm, to find the shortest path of the v0 vertex to the rest Vertex v p[v] and the value of the weighted length d[v]////////////////////////////////////////   
         Path_dijkstra (mgraph g, int v0, Patharc *p, shortpathtable *d) {int v,w,k,min;                  int Final[maxvex];   
             /* Final[w]=1 indicates the shortest path to the vertex v0 to VW * * * Initialization data/* for (v=0; v<g.numvertexes; v++) {                   FINAL[V] = 0;         /* All vertices initialized to unknown shortest path state */(*D) [v] = g.arc[v0][v];                    /* will be connected with the v0 point of the vertex plus weight * * (*P) [v] = 0;                       /* Initialize path array p is 0 */} (*D) [v0] = 0;                      /* V0 to V0 path is 0 */final[v0] = 1;   
         /* V0 to V0 do not require the path////* Start the main loop, each time to get v0 to a v vertex shortest path/for (v=1; v<g.numvertexes; v++)                   {min=infinity;  /* Current known distance from V0 Vertex * * for (w=0 w<g.numvertexes; w++)/* Look for the nearest vertex to the v0 * * 
                 if (!final[w] && (*d) [w]<min) {k=w;          min = (*d) [w];                    * W vertex closer to V0 vertex/}} Final[k] = 1;  
            /* To add the nearest vertex found to the S set///////* Fix the current shortest path and distance * * for (w=0 w<g.numvertexes; w++) {   
                 * * If the path through the V vertex is shorter than the current path (!final[w) && (min+g.arc[k][w]< (*D) [W]) {/* description found a shorter path, modify d[w] and P[w] */(*D) [W] = min + g.arc[k][w];   
                 * Modify the current path length * * (*P) [W]=k;   }   
            }   
         }  
    }

The algorithm is applied to the greedy idea, in fact if S (i,j) ={vi .... Vk.. Vs... VJ} is the shortest path from vertex i to J, and K and S are an intermediate vertex on this path, then S (k,s) must be the shortest path from K to S. This is easy to prove because S (i,j) =s (i,k) +s (k,s) +s (s,j), adding S (k,s) is not the shortest distance from K to S, there must be another edge to make I to J distance shortest: s ' (i,j) =s (i,k) +s ' (k,s) +s (s,j) <s (i , j), contradictions. So based on this assumption, the shortest path of I to J is actually asked for all the shortest paths in the middle process.

Careful comparison of the algorithm with the minimum spanning tree algorithm prim, it is not a bit similar. But in fact there's a big difference between the two, the most critical point is that prim updates the distance between the accessed collection and the Unreachable collection (not the vertex of the minimum spanning tree), while the Dijkstra algorithm updates the source point V0 to the Unreachable collection (points not included in the shortest path), comparing the code as follows:

    for (j = 1; j<g.numvertexes; j +)/loop all vertices  
    {  
        if (Lowcost[j]!= 0 && g.arc[k][j] < Lowcost[j])  
        { The c4/>//of vertices with subscript k are smaller than the spanning tree weights which were not added before these vertices  
            lowcost[j] = g.arc[k][j];  
            ADJVEX[J] = k;              Save the vertex labeled K to Adjvex} for  
    (w=0 w<g.numvertexes; w++)   
    {/  
        * If the path passing through the V vertex is shorter than the current path's length * *  
        if (!final[w] && (min+g.arc[k][w]< (*D) [W]   
        ) {/   
            * description found a shorter path, modify d[w] and P[w]/  
            (*D) [W] = min + g.arc[k][w];/* Modify current path length   
            /(*P) [W]=k;   
        }   
    }   

The final output D array and p array, assuming the D array is {0,1,4,7,5,8,10,12,16},p array is {0,0,1,4,2,4,3,6,7}. The D array describes the shortest distance between vertices to each vertex, such as d[8]=16 description v0 to the V8 shortest distance of 16, through the P array to know the way the path: p[8]=7 description V8 vertex precursor is v7, and then p[7]=6 Get v0->v1->v2->v4->v3->v6->v7->v8; by analogy

This algorithm can see that the time complexity is O (n^2) from nested loops, if the shortest path of any vertex to all other vertices can be called the Dijkstra algorithm for n vertices, and the algorithm complexity O (n^3). In this paper, we introduce a time complexity O (n^3) algorithm-Freud (Floyd), the algorithm is very elegant and concise.


Ii. Freud (Floyd) algorithm


To understand the subtleties of the algorithm, first look at the simplest case. The left part of the following figure is one of the simplest 3 vertex connected network graphs.

Define two array d[3][3] and p[3][3],d the shortest path weights and matrices representing vertices to vertices, p represents the precursor matrix of the minimum path of the corresponding vertex. Before we parse any vertices, we name D d^-1, which is actually the adjacency matrix of the initial graph. The p is named P^-1 and initialized to the matrix shown in the diagram.
First, we analyze the shortest distance from which all vertices reach another vertex after v0. Because there are only three vertices, you need to view v1->v0->v2, get d^-1 [1][0] + d^-1 [0][2] = 2+1 = 3. d^-1 [1][2] indicates that the V1->V2 weight is 5, we found d^-1 [1][2] > d^-1 [1][0] + d^-1 [0][2], the popular saying is that the v1->v0->v2 than the direct v1->v2 distance still closer. So we let d^-1 [1][2] = d^-1 [1][0] + d^-1 [0][2], the same d^-1 [2][1] = 3, so we have the D0 matrix. Because of the changes, so the P-matrix corresponding to the p-1[1][2] and p-1[2][1] also modified to the current relay vertex v0 subscript 0, so there is P0. Other words:

From here, we have seen that the Floyd algorithm is a dynamic programming algorithm, why it is elegant.
In layman's terms, our goal is to find the shortest path from point I to J. From the point of view of dynamic planning, we need to make a new interpretation of this goal (this annotation is the most creative essence of dynamic programming), the Floyd algorithm added this concept
D^k (I,J): Represents the shortest path from I to J that is not indexed to a point that is larger than K.
The important thing about this limitation is that it limits the concept of the shortest path so that the restriction has the opportunity to satisfy the iterative relationship, which is the study of the hypothesis that d^ (k-1) (I,J) is known to deduce D^k (I,J).
Assuming I'm going to get D^k (I,J) Now, and d^ (k-1) (I,J) is known, then I can look at the problem in two different ways: 1. D^k (I,J) along the way through a point k;2. D^k (I,J) does not pass the point K.

(1) If the shortest path passes through point K, then it is clear that d^k (i,j) = d^ (k-1) (i,k) + d^ (k-1) (k,j), why d^ (k-1). Because of the (i,k) and (K,j), because K itself is the source (or endpoint), plus we're asking for D^k (I,J), it satisfies the condition that does not go through a point that is larger than K.

(2) If the shortest path does not pass the point K, D^k (i,j) =d^ (k-1) (I,J) can be obtained. So we get the formula:

D^k (i,j) = min (d^ (k-1) (i,j), d^ (k-1) (i,k) +d^ (k-1) (k,j));

Next, in fact is on the basis of D0 and P0, continue to process all vertices after V1 and v2 to reach another vertex shortest path, get D1 and P1, D2 and P2 complete all vertices to all vertices of the shortest path calculation.

First, we prepare two matrices d^-1 and p^-1 for the left net graph of the following graph, that is, the adjacency matrix of the net graph and the matrix of the first set as p[j][j] = J, which is mainly used to store the path.

The specific code below, note is: The shortest path to all vertices to all vertices, so pathmatirx and shortpathtable are two-dimensional arrays.

    /* Floyd algorithm to find the shortest path of the vertices V to the rest of the vertex w in the net graph G p[v][w] and the weighted length d[v][w].   
        */void Shortestpath_floyd (Mgraph G, Patharc *p, shortpathtable *d) {int v,w,k;   
            For (v=0 v<g.numvertexes; ++v)/* Initialize D and p */{for (w=0; w<g.numvertexes; ++w)   {(*d) [v][w]=g.arc[v][w];             /* D[v][w] value is the right value between the corresponding points * * (*p) [V][w]=w; /* Initialize P */}} for (K=0 k<g.numvertexes; ++k) {for (v=0; V&L T g.numvertexes; ++V) {for (w=0; w<g.numvertexes; ++w) {if ( (*d) [V]  
                        [w]> (*d) [v][k]+ (*d) [k][w]) {/* If the path through the subscript k vertex path is shorter than the original two points between the paths * * * (*d) [V]   [W]= (*d) [v][k]+ (*d) [k][w];              /* Set the current two-point weight value to a smaller one/* (*P) [v][w]= (*p) [v][k];  
          /* The path is set to the vertex with subscript k */}      }  
            }  
        }  
    }   

The following detailed procedure is described below:
(1) The program begins to run, and the 第4-11 line is initialized with D and P, making them the two matrices of the above figure. From the matrix also obtained, the V0-&GT;V1 path weight is 1,v0->v2 path weight value is 5,v0->v3 boundless line, so the path weight is a maximum value of 65535.
(2) the 12th to 25th Line, is the main algorithm of the loop, a total of three layers of nesting, K represents the relay vertex subscript. V represents the starting vertex, and W represents the end vertex.
(3) When k = 0 o'clock, that is, all vertices are passed v0 relay, calculate whether there is a shortest path changes. Unfortunately the result is that there is no change, as shown in the following figure.

(4) When k = 1 o'clock, that is, all vertices are passed through the V1 relay. At this time, when V = 0 o'clock, originally d[0][2] = 5, now because of d[0][1] + d[1][2] = 4. Therefore, by the 20th line of the code, the two take its minimum value, get d[0][2] = 4, the same can be d[0][3] = 8, d[0][4] = 6, when V = 2, 3, 4 o'clock, also modified some of the data, see the figure on the left of the picture dotted box data. Because of these minimum weights, the path matrix P also has to be processed and changed to the current P[v][k] value, as shown in line 21st of the code.

(5) Next is k = 2, until the end of 8, indicating that for each vertex to do a relay to get the results of the calculation, of course, we also need to be clear, d^0 is based on D^-1, D^1 is based on d^0, ..., D^8 is based on d^7. Finally, when k = 8 o'clock, two matrix data is shown in the following figure.

So how do we get a specific shortest path from the path array of p? Take V0 to V8 for example, from the right figure of the above Figure V8 column, p[0][8]= 1, get to go through the vertex v1, and then replace 1 0, get p[1][8] = 2, description to go through V2, and then 2 to replace 1 get p[2][8] = 4, description to go through V4, then 4 replace 2, get p[4][8] = 3, stating that after 3, ..., it is easy to push out the final shortest path value of V0->V1->V2->V4->V3->V6->V7->V8.

The display code that asks for the shortest path between all vertices can be written like this:

    For (v=0 v<g.numvertexes; ++v)   
    {for   
        (w=v+1; w<g.numvertexes; w++)   
        {  
            printf (v%d-v%d Weight:%d ", V,w,d[v][w]);  
            K=P[V][W];                /* Get the first path vertex subscript  
            /printf ("Path:%d", v);    /* Print source point  
            /while (K!=W)/                * If the path vertex subscript is not the endpoint *  
                /{printf ("->%d", k);    * * Print path vertex  
                /k=p[k][w];            /* Get the next path vertex subscript  
            *  
            /} printf ("->%d\n", W);    /* Print end  
        /} printf ("\ n");  
    }  

If only require V0 to V8 shortest path, do not need the outer two-layer cycle, direct v=0,w=8 can be.

It is known from the execution of the code that the algorithm requires a triple loop to correct the D array and the P array, so the complexity O (n^3).

Summary: If the two algorithms for finding the shortest path are still valid for the directed graph, the difference between the two is only the symmetry of the adjacency matrix.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.