catalogue
π Breadth first traversal of trees and graphs
π Single source shortest path (naive Dijkstra) (there must be no negative weight edge)
→ heap optimization Dijkstra (to be continued...)
π Single source shortest path with negative weight edge (Bellman Ford, spfa)
→ Bellman Ford (limited number of sides)
π‘ Similarities and differences between Bellman Ford and Dijkstra
β Why can't Dijkstra be used in graphs with negative weights and Bellman Ford can?
spfa judgment negative ring (to be continued...)
π Multi source shortest path Floyd
π Minimum spanning tree (Prim,Kruskal)
Not long after learning graph theory, The process is happy and painful, Some of the bosses' conclusions are obscure, And full of beauty, Some may not be widely recognized, but they are still sharp and have their own merits on specific issues, What are you afraid of? The truth is infinite. There is an inch of joy.
π DFS
Β
π BFS
Β
π Breadth first traversal of trees and graphs
→ topological sorting
It is basically the same as the breadth first traversal of the graph, An array in [] representing the penetration of each vertex is also added,
1. Put the points with zero degree into the queue
2. Continuously cycle the following steps
Determine whether the stack is empty, If empty, the cycle ends, otherwise:
Take out the team leader, When you delete this node, the associated edge, The point penetration adjacent to it is reduced by 1, If the penetration is zero, Then put it in the queue
3. If the number of nodes in the queue is less than the summary points, It means that there must be a loop in the figure
Example:
Input example:
3 3 1 2 2 3 1 3
Output example:
1 2 3
#include <iostream> #include <cstring> #include <algorithm> using namespace std; const int N = 1e5+10; int n, m; int h[N], e[N], ne[N], idx; int q[N]; //queue int in[N]; //Penetration void add(int a, int b) { e[idx] = b, ne[idx] = h[a], h[a] = idx ++; } bool topSort() { int front = -1, rear = -1; for(int i = 1; i <= n; i ++) if(!in[i]) q[++rear] = i; while(front != rear) { int t = q[++front]; for(int i = h[t]; i != -1; i = ne[i]) { int j = e[i]; in[j]--; if(!in[j]){ q[++rear] = j; } } } return rear == n-1; //The sequence stored in q is actually a topological sequence } int main() { cin >> n >> m; memset(h, -1, sizeof h); int a, b; while (m -- ) { scanf("%d%d", &a, &b); add(a, b); in[b] ++; } if(topSort()){ for(int i = 0; i < n; i ++) printf("%d ", q[i]); }else{ cout << "-1"; } return 0; }
π shortest path
π Single source shortest path (naive Dijkstra) (there must be no negative weight edge)
→ heap optimization Dijkstra (to be continued...)
π Single source shortest path with negative weight edge (Bellman Ford, spfa)
→ Bellman Ford (limited number of sides)
When the k-th update operation is performed, the shortest path can be guaranteed to move from the starting point to each point less than k times
Assuming that point 1 to point n are reachable, each point starts in the direction pointed at the same time, and updates the shortest distance of adjacent points. Through n-1 operations, if there is no negative ring in the graph, point 1 will reach point n. if there is a negative ring in the graph, it will be updated after n-1 relaxation
π‘ Similarities and differences between Bellman Ford and Dijkstra
Dijkstra | bellman-ford | |
with | Similar to Dijkstra, Bellman Ford algorithm is based on relaxation operation, that is, the estimated shortest path value is gradually replaced by a more accurate value until the optimal solution is obtained. In the two algorithms, the estimated distance between each edge is larger than the real value during calculation, and is replaced by the minimum length of the newly found path. | |
different | The greedy method is used to select the unprocessed node with the minimum weight, and then the edge is relaxed | Directly relax all edges for n-1 times (or k times, and artificially limited number of edges) , where n is the number of points in the graph. In the repeated calculation, the number of edges that have calculated the correct distance continues to increase until all edges have calculated the correct path. This strategy makes the Behrman Ford algorithm more suitable for more kinds of inputs than the dikoscher algorithm. |
β Why can't Dijkstra be used in graphs with negative weights and Bellman Ford can?
Quote AcWing's silly interpretation π
Example:
Input example:
3 3 1 1 2 1 2 3 1 1 3 3
Output example:
3
for n times
for all edges a,b,w (relax operation)
Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β dist[b] = min(dist[b],back_dist[a] + w)
be careful:
- The back [] array is a backup of the dist [] array after the last iteration. Since each point starts outward at the same time, the dist [] array needs to be backed up. If it is not backed up, a series effect will occur and the next point will be affected
- INF is a definite value, not really infinite. It will be affected by other values. dist[n] can be greater than a number of the same order of magnitude as INF (my understanding) π No matter how strong a man is, he has weaknesses, but a skinny camel is bigger than a horse. Even if he meets a negative power, It is also a magnitude that can not be underestimated and belongs to a realm that ordinary people can't reach)
#include <iostream> #include <cstring> #include <algorithm> using namespace std; const int N = 510, M = 10010, INF = 0x3f3f3f3f; struct Edge{ int a, b, w; }e[M]; int n,m,k; int dist[N], back_dist[N];//Shortest distance void bellman_ford() { memset(dist, 0x3f, sizeof dist);//β remember to initialize dist[1] = 0; for(int i = 0; i < k; i++) { memcpy(back_dist, dist, sizeof dist);//Remember the last time for(int j = 0; j < m; j++) { int a = e[j].a, b = e[j].b, w = e[j].w; dist[b] = min(dist[b], back_dist[a]+w);//Here you need to update with back_dist } } } int main() { cin >> n >> m >> k; int a,b,w; for(int i = 0; i < m; i++) { scanf("%d%d%d", &a, &b, &w); e[i] = {a, b, w}; } bellman_ford(); if(dist[n] > INF/2) cout << "impossible"; else cout << dist[n]; return 0; }
→ SPFA (queue optimization for Bellman Ford) (it is required that the figure does not contain negative rings)
This step of analyzing Belman Ford dist[b] = min(dist[b],back[a] + w), When do we need to update dist[b]? Yes, only when back_dist[a] It is only necessary when it becomes smaller (predecessors plant trees and later enjoy the cool). According to this, we use the queue to optimize the operation, The points to be updated are stored in the queue, which is very similar to wide search
Β
Input example:
3 3 1 2 5 2 3 -3 1 3 4
Output example:
2
#include <iostream> #include <queue> #include <cstring> #include <algorithm> using namespace std; const int N = 1e5+10, INF = 0x3f3f3f3f; int n,m; int h[N],e[N],ne[N],w[N],idx; int dist[N]; bool st[N]; void add(int a, int b, int c) { e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx ++; } int spfa() { memset(dist, 0x3f, sizeof dist); dist[1] = 0; queue<int > q; q.push(1); st[1] = true; while(q.size()) { int t = q.front(); q.pop(); st[t] = false; for(int i = h[t]; i != -1; i = ne[i]) { int j = e[i]; if(dist[t]+w[i] < dist[j]){ dist[j] = dist[t]+w[i]; if(!st[j]) //Is it already in the queue { st[j] = true; q.push(j); } } } } return dist[n]; } int main() { cin >> n >> m; memset(h, -1, sizeof h); int a, b, c; for (int i = 0; i < m; i ++ ) { scanf("%d%d%d", &a, &b, &c); add(a, b, c); } int res = spfa(); if(res==INF) cout << "impossible"; else cout << res; return 0; }
spfa judgment negative ring (to be continued...)
π Multi source shortest path Floyd
Based on dynamic programming, The shortest distance from I to j is d[i, j] = min{d[i, j], d[i, k]+d[k, j]}, On the whole, all we have to do is to enumerate all the cases (1) ≤ i , j ,k ≤ n)
Input example:
3 3 2 1 2 1 2 3 2 1 3 1 2 1 1 3
Output example:
impossible 1
Β
#include <cstring> #include <iostream> #include <algorithm> using namespace std; const int N = 210, INF = 0x3f3f3f3f; int n, m, k; int d[N][N]; void floyd() { for (int k = 1; k <= n; k ++ ) for (int i = 1; i <= n; i ++ ) for (int j = 1; j <= n; j ++ ) d[i][j] = min(d[i][j], d[i][k] + d[k][j]); } int main() { cin >> n >> m >> k; memset(d, 0x3f, sizeof d); for (int i = 1; i <= n; i ++ ) d[i][i] = 0; int a, b, c; while (m -- ) { scanf("%d%d%d", &a, &b, &c); d[a][b] = min(d[a][b], c); } floyd(); while (k --) { scanf("%d%d", &a, &b); int res = d[a][b]; if (res > INF/2) cout << "impossible" << '\n'; else cout << res << '\n'; } return 0; }
Β