1 Dijkstra (single source shortest path problem)
1.1 minimum distance
1.1.1 pseudo code
//Figure G is generally set as a global variable; Array d is the shortest path length from the source point to each point, and s is the starting point Dijkstra(G, d[], s){ Initialization for (n cycles) { U = the label of the vertex that makes d[u] the smallest but has not been accessed; u has been visited; for (all vertices V that can be reached from u) { if(v is not accessed & & taking u as the intermediary point makes the shortest path d[v] from s to V better){ Optimize d[v]; } } } }
1.1.2 adjacency matrix
- For small points (no more than 1000)
- Time complexity
- Outer loop O(V) [V is the number of vertices] and inner loop (O(V) is needed to find the smallest d[u], O(V) is needed to enumerate V, and the total time complexity is O(V * (V + V)) = O(V2)
const int MAXV = 1000;//max vertex const int INF = 0x3fffffff; int G[MAXV][MAXV], n;//Number of graphs and vertices int d[MAXV];//The shortest path from the starting point to each point bool vis[MAXV] = {false};//Whether the tag is accessed void Dijkstra(int s){//s starting point fill(d, d + MAXV, INF);//Assign the entire array d to INDF, which is not reachable d[s] = 0;//The distance from the starting point to itself is 0 for (int i = 0; i < n; ++i)//Circular c times { int u = - 1, min = INF;//U makes d[u] minimum, MIN stores the minimum d[u] for (int j = 0; j < n; ++j)//Find the smallest d [] of the unreachable vertices { if(vis[j] == false && d[j] < min){ u = j; min = d[j]; } } //No d[u] less than INF can be found, indicating that the remaining vertices are not connected to the starting point s if(u == -1) return; vis[u] = true;//Tag u has been accessed for (int v = 0; v < n; ++v) { //If V is not accessed & & u can reach V & & make u as the intermediary point can make d[v] better if(vis[v] == false && G[u][v] != INF && d[u] + G[u][v] < d[v]){ d[v] = d[u] + G[u][v];//Optimizing d[v] } } } }
1.1.3 adjacency table
- Time complexity
- Outer loop O(V) [V is the number of vertices] and inner loop (finding the smallest d[u] requires O(V), enumerating V requires O(adj[u].size()), the total number of enumerating V is O(∑ u=0n − 1adj [u]. Size() \ sum {u = 0} ^ {n-1} adj [u]. Size() ∑ u=0n − 1 adj[u].size()) = O(E), and the total time complexity is O(V2 + E)
struct node { int v;//Target vertex of edge int dis;//Border rights }; const int MAXV = 1000;//max vertex const int INF = 0x3fffffff; vector<node> Adj[MAXV];/// / adjacency list int n;//Vertex number int d[MAXV];//The shortest path from the starting point to each point bool vis[MAXV] = {false};//Whether the tag is accessed void Dijkstra(int s){//s starting point fill(d, d + MAXV, INF);//Assign the entire array d to INDF, which is not reachable d[s] = 0;//The distance from the starting point to itself is 0 for (int i = 0; i < n; ++i)//Circular c times { int u = - 1, min = INF;//U makes d[u] minimum, MIN stores the minimum d[u] for (int j = 0; j < n; ++j)//Find the smallest d [] of the unreachable vertices { if(vis[j] == false && d[j] < min){ u = j; min = d[j]; } } //No d[u] less than INF can be found, indicating that the remaining vertices are not connected to the starting point s if(u == -1) return; vis[u] = true;//Tag u has been accessed for (int j = 0; j < Adj[u].size(); ++j) { int v = Adj[u][j].v;//The vertex v that u can reach can be obtained directly by adjacency table if(vis[v] == false && d[u] + Adj[u][j].dis < d[v]){ //V is not accessed & & using u as a mediation point can make d[v] better d[v] = d[u] + Adj[u][j].dis;//Optimizing d[v] } } } }
1.1.4 optimization and points for attention
- optimization
- The time complexity of the above two algorithms is O(V2). Since each vertex must be marked as accessed, the O(V) of the outer loop cannot be avoided, but the one looking for the smallest d[u] can not reach the length of O(V). Heap optimization can be used to reduce the complexity. The simplest way to write is to directly use the priority queue of STL, so that the time of adjacent table can be reduced Inter complexity reduced to O(VlogV+E)
- Be careful
- If we want undirected edge, we only regard undirected edge as two opposite directed edges.
1.1.5 example
- Problem Description:
Input Specification:
Each input file contains one test case. For each case, the first line contains three positive integer n(<=1000), m , s, which are the number of nodes, the number of edge, and start of nodes.Then m lines follow, each describes each edge by 3 integers, which are starting node, ending node, and weight of node.
Output Specification:
output in a line the number of nodes distance which from starting node to each nodes .
Sample Input: 6 8 0 0 1 1 0 3 4 0 4 4 1 3 2 2 5 1 3 2 2 3 4 3 4 5 3 Sample Output: 0 1 5 3 4 6
- Solution code
#include <cstdio> #include <algorithm> using std::fill; const int MAXV = 1000; const int INF = 0x3fffffff; int G[MAXV][MAXV]; bool vis[MAXV] = {false}; int d[MAXV]; int n, m, s; void Dijkstra(int s){ fill(d, d + MAXV, INF); d[s] = 0; for (int i = 0; i < n; ++i) { int u = -1, min = INF; for (int j = 0; j < n; ++j) { if(vis[j] == false && d[j] < min){ u = j; min = d[j]; } } if(u == -1) return; vis[u] = true; for (int v = 0; v < n; ++v) { if(vis[v] == false && G[u][v] != INF && d[u] + G[u][v] < d[v]){ d[v] = d[u] + G[u][v]; } } } } int main(int argc, char const *argv[]) { int u, v ,w; scanf("%d%d%d", &n, &m, &s);//Vertex number, edge number, start number fill(G[0], G[0] + MAXV * MAXV, INF);//Initialization diagram G for (int i = 0; i < m; ++i) { scanf("%d%d%d", &u, &v, &w);//Input the edge weight of u, v and U - > v G[u][v] = w; } Dijkstra(s); for (int i = 0; i < n; ++i) { printf("%d ", d[i]); } return 0; } /* 6 8 0 0 1 1 0 3 4 0 4 4 1 3 2 2 5 1 3 2 2 3 4 3 4 5 3 */
1.2 shortest path
1.2.1 pseudo code
//Figure G is generally set as a global variable; Array d is the shortest path length from the source point to each point, and s is the starting point Dijkstra(G, d[], s){ Initialization for (n cycles) { U = the label of the vertex that makes d[u] the smallest but has not been accessed; u has been visited; for (all vertices V that can be reached from u) { if(v is not accessed & & taking u as the intermediary point makes the shortest path d[v] from s to V better){ Optimize d[v]; Let the precursor of v be u; } } } }
1.2.2 adjacency matrix
const int MAXV = 1000; const int INF = 0x3ffffff; int G[MAXV][MAXV], n; bool vis[MAXV] = {false}; int pre[MAXV]; int d[MAXV]; void Dijkstra(int s){//Find the precursor of each node in the shortest path fill(d, d + MAXV, INF); for (int i = 0; i < n; ++i)//Newly added { pre[i] = i;//The precursor of each node in the initial state is itself } for (int i = 0; i < n; ++i) { int u = -1, min = INF; for (int j = 0; j < n; ++j) { if(vis[j] == false && d[j] <min){ u = j; min = d[j]; } } if(u == -1) return; vis[u] = true; for (int v = 0; v < n; ++v) { if(vis[v] == false && G[u][v] != INF && d[u] + G[u][v] < d[v]){ d[v] = d[u] + G[u][v]; pre[v] = u; } } } } void DFS(int s, int v){//s: Start point number; v: currently accessed vertex number (recursion from end point) if(v == s){ printf("%d\n", s); return; } DFS(s, pre[v]);//Recursive access to the precursor node of V pre[v] printf("%d\n", v);//After return ing from the deepest point, output the vertex number of each layer }
1.2.3 adjacency table
struct node { int v; int dis; }; const int MAXV = 1000; const int INF = 0x3ffffff; vector<node> Adj[MAXV];/// / adjacency list int n; bool vis[MAXV] = {false}; int pre[MAXV]; int d[MAXV]; void Dijkstra(int s){//Find the precursor of each node on the shortest path fill(d, d + MAXV, INF); for (int i = 0; i < n; ++i)//Newly added { pre[i] = i;//The precursor of each node in the initial state is itself } for (int i = 0; i < n; ++i) { int u = -1, min = INF; for (int j = 0; j < n; ++j) { if(vis[j] == false && d[j] <min){ u = j; min = d[j]; } } if(u == -1) return; vis[u] = true; for (int j = 0; j < Adj[u].size(); ++j) { int v = Adj[u][j].v; if(vis[v] == false && d[u] + Adj[u][j].dis < d[v]){ d[v] = d[u] + Adj[u][j].v; pre[v] = u; } } } } void DFS(int s, int v){//s: Start point number; v: currently accessed vertex number (recursion from end point) if(v == s){ printf("%d\n", s); return; } DFS(s, pre[v]);//Recursive access to the precursor node of V pre[v] printf("%d\n", v);//After return ing from the deepest point, output the vertex number of each layer }
1.3 related applications
When there is more than one shortest path from the starting point to the end point, the topic will give the second scale (the first scale is the distance), and it is required to select the best one of the second scale from all the shortest paths. The second scale is commonly used in the following three methods or combinations:
- 1 new edge right
The cost of U - > V is represented by cost[u][v], and an array c [] is added. The minimum cost from the starting point s to the vertex u is c[u]. When initializing, c[s] is 0, and the rest c[u] is INF.
for (int v = 0; v < n; ++v) { //If v is not accessed & & u can reach v if(vis[v] == false && G[u][v] != INF){ if(d[u] + G[u][v] < d[v]){//Taking u as the intermediary point can make d[v] better d[v] = d[u] + G[u][v]; c[v] = c[u] + cost[u][v]; }else if(d[u] + G[u][v] == d[v] && cost[u] + cost[u][v] < cost[v]){ c[v] = c[u] + cost[u][v];//Whether the shortest distance can make c[v] better } } }
- 2. New rights
Take the newly added point weight as an example to represent the materials that can be collected in the city, use weight[u] as the number of materials in the city u (input by the title), and add an array w [], so that the maximum materials that can be collected from the starting point s to the vertex u are w[u], only w[s] and the rest w[u] are 0 when initializing.
for (int v = 0; v < n; ++v) { //If v is not accessed & & u can reach v if(vis[v] == false && G[u][v] != INF){ if(d[u] + G[u][v] < d[v]){//Taking u as the intermediate point can make d[v] better d[v] = d[u] + G[u][v]; w[v] = w[u] + weight[u][v]; }else if(d[u] + G[u][v] == d[v] && w[u] + weight[v] > w[v]){ w[v] = w[u] + weight[v];//Whether the shortest distance can make w[v] better } } }
- 3 find the shortest path.
Just add an array num [] to make the shortest path from the starting point s to the vertex u be num[u]. During initialization, only num[s] is 1, and the rest num[u] is 0.
for (int v = 0; v < n; ++v) { //If v is not accessed & & u can reach v if(vis[v] == false && G[u][v] != INF){ if(d[u] + G[u][v] < d[v]){//Taking u as the intermediate point can make d[v] better d[v] = d[u] + G[u][v]; num[v] = num[u]; }else if(d[u] + G[u][v] == d[v]){ num[v] += um[u];//Whether the shortest distance can make w[v] better } } }