Shortest Path Algorithms (Rotation)
Posted by xmarcusx on Mon, 15 Jul 2019 21:31:40 +0200
The shortest path problem aims to find the shortest path between two nodes in the graph. There are four commonly used algorithms. Note whether the graph is undirected or directed
Dijkstra's
1 Dijkstra's algorithm solves the shortest path from a single source point to another vertex in the graph. It can only solve the problem of non-negative weight
2 Dijkstral can only find the shortest distance between any point and the source point (it can not find the shortest distance between any two points). It is also applicable to digraphs and undirected graphs with O(n^2) complexity.
3. The process of the algorithm:
1. Set the vertex set S and continue to make greedy choices to expand the set. A vertex belongs to set S if and only if the shortest path length from the source point to that point is known.
2 Initially, S contains only sources. Let U be a vertex of G. The path from source to U and only passing through the vertex of S in the middle is called a special path from source to U, and the shortest special path corresponding to each current vertex is distanced by dis array.
The 3D ijkstra algorithm extracts the vertex u with the shortest special length from V-S each time, adds u to S, and modifies the dis array. Once S contains all the vertices in V, the dis array records the shortest path length from the source point to other vertices.
4 Templates:
Without optimization, time complexity o(n^2)
-
#define MAXN 1010
-
#define INF 0xFFFFFFF
-
int value[MAXN][MAXN];
-
int dis[MAXN];
-
int father[MAXN];
-
int vis[MAXN];
-
-
void input(){
-
int star , end , v;
-
scanf("%d%d" , &n , &m);
-
-
for(int i = 1 ; i <= n ; i++){
-
for(int j = 1; j <= n ; j++)
-
value[i][j] = INF;
-
}
-
for(int i = 0 ; i < m ; i++){
-
scanf("%d%d%d" , &star , &end , &v);
-
if(value[star][end] == INF)
-
value[star][end] = value[end][star] = v;
-
else{
-
if(v < value[star][end])
-
value[star][end] = value[end][star] = v;
-
}
-
}
-
-
void dijkstra(int s){
-
memset(vis , 0 , sizeof(vis));
-
memset(father , 0 , sizeof(father));
-
-
for(int i = 1 ; i<= n ; i++)
-
dis[i] = INF;
-
dis[s] = 0;
-
for(int i = 1 ; i <= n ; i++){
-
int pos;
-
pos = -1;
-
for(int j = 1 ; j <= n ;j++){
-
if(!vis[j] && (pos == -1 || dis[j] < dis[pos]))
-
pos = j;
-
}
-
vis[pos] = 1;
-
for(int j = 1 ; j <= n ; j++){
-
if(!vis[j] && (dis[j] > dis[pos] + value[pos][j])){
-
dis[j] = dis[pos] + value[pos][j];
-
father[j] = pos;
-
}
-
}
-
}
-
}
-
#define MAXN 1010
-
#define INF 0xFFFFFFF
-
int value[MAXN][MAXN];
-
int dis[MAXN];
-
int father[MAXN];
-
int vis[MAXN];
-
-
void input(){
-
int star , end , v;
-
scanf("%d%d" , &n , &m);
-
-
for(int i = 1 ; i <= n ; i++){
-
for(int j = 1; j <= n ; j++)
-
value[i][j] = INF;
-
}
-
for(int i = 0 ; i < m ; i++){
-
scanf("%d%d%d" , &star , &end , &v);
-
if(value[star][end] == INF)
-
value[star][end] = value[end][star] = v;
-
else{
-
if(v < value[star][end])
-
value[star][end] = value[end][star] = v;
-
}
-
}
-
-
void dijkstra(int s){
-
memset(vis , 0 , sizeof(vis));
-
memset(father , 0 , sizeof(father));
-
-
for(int i = 1 ; i<= n ; i++)
-
dis[i] = INF;
-
dis[s] = 0;
-
for(int i = 1 ; i <= n ; i++){
-
int pos;
-
pos = -1;
-
for(int j = 1 ; j <= n ;j++){
-
if(!vis[j] && (pos == -1 || dis[j] < dis[pos]))
-
pos = j;
-
}
-
vis[pos] = 1;
-
for(int j = 1 ; j <= n ; j++){
-
if(!vis[j] && (dis[j] > dis[pos] + value[pos][j])){
-
dis[j] = dis[pos] + value[pos][j];
-
father[j] = pos;
-
}
-
}
-
}
-
}
-
Optimized, time complexity is o(mlogn);
-
-
#include<utility>
-
typedef pair<int , int>pii;
-
priority_queue<pii,vector<pii>,greater<pii> >q;
-
#define MAXN 1010
-
#define INF 0xFFFFFFF
-
int n , m;
-
int first[MAXN] , next[MAXN];
-
int u[MAXN] , v[MAXN] , value[MAXN];
-
int vis[MAXN];
-
int dis[MAXN];
-
-
-
void input(){
-
scanf("%d%d" , &n , &m);
-
-
for(int i = 1 ; i <= n ; i++)
-
first[i] = -1;
-
for(int i = 1 ; i <= m ; i++){
-
scanf("%d%d" , &u[i] , &v[i] , &value[i]);
-
next[i] = first[u[i]];
-
first[u[i]] = i;
-
}
-
}
-
-
-
void Dijkstra(int s){
-
memset(vis , 0 , sizeof(vis));
-
-
for(int i = 1 ; i <= n ; i++)
-
dis[i] = INF;
-
dis[s] = 0;
-
while(!q.empty())
-
q.pop();
-
q.push(make_pair(dis[s] , s));
-
while(!q.empty()){
-
pii u = q.top();
-
q.pop();
-
int x = u.second;
-
if(vis[x])
-
continue;
-
vis[x] = 1;
-
for(int i = first[x] ; i != -1 ; i = next[i]){
-
if(dis[v[e]] > dis[x] + value[i]){
-
dis[v[i]] = dis[x] + value[i];
-
q.push(make_pair(dis[v[i] , v[i]));
-
}
-
}
-
}
-
}
-
Optimized, time complexity is o(mlogn);
-
-
#include<utility>
-
typedef pair<int , int>pii;
-
priority_queue<pii,vector<pii>,greater<pii> >q;
-
#define MAXN 1010
-
#define INF 0xFFFFFFF
-
int n , m;
-
int first[MAXN] , next[MAXN];
-
int u[MAXN] , v[MAXN] , value[MAXN];
-
int vis[MAXN];
-
int dis[MAXN];
-
-
-
void input(){
-
scanf("%d%d" , &n , &m);
-
-
for(int i = 1 ; i <= n ; i++)
-
first[i] = -1;
-
for(int i = 1 ; i <= m ; i++){
-
scanf("%d%d" , &u[i] , &v[i] , &value[i]);
-
next[i] = first[u[i]];
-
first[u[i]] = i;
-
}
-
}
-
-
-
void Dijkstra(int s){
-
memset(vis , 0 , sizeof(vis));
-
-
for(int i = 1 ; i <= n ; i++)
-
dis[i] = INF;
-
dis[s] = 0;
-
while(!q.empty())
-
q.pop();
-
q.push(make_pair(dis[s] , s));
-
while(!q.empty()){
-
pii u = q.top();
-
q.pop();
-
int x = u.second;
-
if(vis[x])
-
continue;
-
vis[x] = 1;
-
for(int i = first[x] ; i != -1 ; i = next[i]){
-
if(dis[v[e]] > dis[x] + value[i]){
-
dis[v[i]] = dis[x] + value[i];
-
q.push(make_pair(dis[v[i] , v[i]));
-
}
-
}
-
}
-
}
Floyd (non-negative weight) is suitable for digraphs and undirected graphs
The idea of 1 floyd is to update the shortest distance by enumerating n points and using the idea of DP. Assuming that the current enumeration reaches the k-th point, there are two arbitrary points I and J. If the K is connected by j k, then we can know that dis [i] [j] = min (dis [i] [j], dis [i] [k] + dis [k] [j]; so long as n points are enumerated. Point, that means that the shortest path between all two points has been completely updated.
2 floydalgorithm It is the simplest algorithm of the shortest path. It can calculate the shortest path between any two points in the graph. The time complexity of floyd algorithm is o(n^3). if it is a graph without edge weight, the distance between two connected points is set to dis[i][j]=1. the two unrelated points are set to infinity. floyd algorithm can judge I
j Are the two points connected?
3 floyd algorithm does not allow all weights to be negative. The shortest distance between any two points can be found. It deals with undirected graphs.
4. The disadvantage is that the time complexity is relatively high and it is not suitable for calculating large amounts of data.
If dis [i] [i]!= 0, then there is a ring.
6 If floyd is used to find the minimum value, dis is initialized as INF, and - 1 is initialized as maximum value.
7. Template:
-
#define INF 0xFFFFFFF
-
#define MAXN 1010
-
int dis[MAXN][MAXN];
-
-
-
void init(){
-
for(int i = 1 ; i <= n ; i++){
-
for(int j = 1 ; j <= n ; j++)
-
dis[i][j] = INF;
-
dis[i][i] = 0;
-
}
-
}
-
-
-
void init(){
-
for(int i = 1 ; i <= n ; i++){
-
for(int j = 1 ; j <= n ; j++)
-
dis[i][j] = -1;
-
}
-
}
-
-
-
void folyd(){
-
for(int k = 1 ; k <= n ; k++){
-
for(int i = 1 ; i <= n ; i++){
-
for(int j = 1 ; j <= n ; j++)
-
if(dis[i][k] != -1 && dis[j][k] != -1)
-
dis[i][j] = min(dis[i][k]+dis[k][j] , dis[i][j]);
-
}
-
}
-
}
-
-
#define INF 0xFFFFFFF
-
#define MAXN 1010
-
int dis[MAXN][MAXN];
-
-
-
void init(){
-
for(int i = 1 ; i <= n ; i++){
-
for(int j = 1 ; j <= n ; j++)
-
dis[i][j] = INF;
-
dis[i][i] = 0;
-
}
-
}
-
-
-
void init(){
-
for(int i = 1 ; i <= n ; i++){
-
for(int j = 1 ; j <= n ; j++)
-
dis[i][j] = -1;
-
}
-
}
-
-
-
void folyd(){
-
for(int k = 1 ; k <= n ; k++){
-
for(int i = 1 ; i <= n ; i++){
-
for(int j = 1 ; j <= n ; j++)
-
if(dis[i][k] != -1 && dis[j][k] != -1)
-
dis[i][j] = min(dis[i][k]+dis[k][j] , dis[i][j]);
-
}
-
}
-
}
-
floyd extension:
How to use floyd to find the point where the shortest path travels: 1. Another matrix P is used here. Its definition is as follows: if the value of P (i j) is p, it means that the shortest path from I to j is I - > p... - > j, that is to say, P is the first point before J in the shortest path from I to J.
The initial value of 2 P matrix is p(ij) = j. With this matrix, it's easy to find the shortest path. For i to j, find P (ij), let p, know the path i - > P. -> j; then go to p(pj), if the value is q, the shortest path from P to j is p - > Q -> j; then go to p(qj), if the value is r, the shortest path from i to q is Q > R -> q; so repeated, the answer will be obtained.
3. But how to fill in the value of P matrix dynamically? Recall that when D (i j) > D (i k) +d (kj), the shortest path from I to j should be changed to I - > k - > k - > j, but the value of D (ik) is known, in other words, I - > k is known, so the first city of K (i - > k) on I - > K is also known, of course, because it is necessary to change to I - >. The first city in P (ij) is p (ik). So once d(ij)>d(ik)+d(kj) is found, p(ik) is deposited in p(ij).
Code 4:
-
int dis[MAXN][MAXN];
-
int path[MAXN][MAXN];
-
-
void floyd(){
-
int i, j, k;
-
-
for (i = 1; i <= n; i++){
-
for (j = 1; j <= n; j++)
-
path[i][j] = j;
-
}
-
for (k = 1; k <= n; k++){
-
for (i = 1; i <= n; i++){
-
for (j = 1; j <= n; j++){
-
if (dis[i][j] > dis[i][k]+dis[k][j]){
-
path[i][j] = path[i][k];
-
dis[i][j] = dis[i][k]+dis[k][j];
-
}
-
}
-
}
-
}
-
}
-
int dis[MAXN][MAXN];
-
int path[MAXN][MAXN];
-
-
void floyd(){
-
int i, j, k;
-
-
for (i = 1; i <= n; i++){
-
for (j = 1; j <= n; j++)
-
path[i][j] = j;
-
}
-
for (k = 1; k <= n; k++){
-
for (i = 1; i <= n; i++){
-
for (j = 1; j <= n; j++){
-
if (dis[i][j] > dis[i][k]+dis[k][j]){
-
path[i][j] = path[i][k];
-
dis[i][j] = dis[i][k]+dis[k][j];
-
}
-
}
-
}
-
}
-
}
2. floyd Solves the Minimum Ring in Rings
1 Why do we need to find the minimum loop before updating the shortest path?
In the k-level loop, we are looking for a ring whose maximum node is k, while the Dist array stores the shortest path through the k-1 node at the end of the k-1 loop, that is to say, the shortest path obtained above does not pass through the k-point, which just meets our requirements. Why? Assuming that the nodes i and j in the ring are directly connected with k, if the shortest path through K is found first, then there will be such a case: the shortest path from i to j passes through K. In this way, no ring can be formed.
2. The proof of the improved algorithm of minimum ring:
The maximum node in a ring is k (the largest number), and the two points connected with it are I and J. The shortest length of the ring is g [i] [k] + G [k] [j] + dis [i] [j] (in the path from I to j, all nodes are less than the shortest path length of k). According to the principle of floyd, dist[i][j] represents the shortest path from I to j after k-1 times of the outermost cycle. In summary, the algorithm can find the smallest ring in the graph.
3 Why do you want a value array?
Because dis arrays are changing all the time, it can't express the distance between the original two points.
4 There must be at least three different points in forming a ring, and two points cannot be considered as rings.
5 code:
-
int mincircle = INF;
-
int dis[MAXN][MAXN];
-
int value[MAXN][MAXN];
-
-
void floyd(){
-
memcpy(value , dis , sizeof(value));
-
for(int k = 1 ; k <= n ; k++){
-
-
for(int i = 1 ; i < k ; i++){
-
for(int j = i+1 ; j < k ; j++)
-
mincircle = min(mincircle , dis[i][j]+value[i][k]+value[k][j]);
-
mincircle = min(mincircle , dis[i][j] +value[i][k]+value[k][j]);
-
}
-
-
for(int i = 1 ; i <= n ; i++){
-
for(int j = 1 ; j <= n ; j++)
-
dis[i][j] = min(dis[i][k]+dis[k][j] , dis[i][j]);
-
}
-
}
-
}
-
int mincircle = INF;
-
int dis[MAXN][MAXN];
-
int value[MAXN][MAXN];
-
-
void floyd(){
-
memcpy(value , dis , sizeof(value));
-
for(int k = 1 ; k <= n ; k++){
-
-
for(int i = 1 ; i < k ; i++){
-
for(int j = i+1 ; j < k ; j++)
-
mincircle = min(mincircle , dis[i][j]+value[i][k]+value[k][j]);
-
mincircle = min(mincircle , dis[i][j] +value[i][k]+value[k][j]);
-
}
-
-
for(int i = 1 ; i <= n ; i++){
-
for(int j = 1 ; j <= n ; j++)
-
dis[i][j] = min(dis[i][k]+dis[k][j] , dis[i][j]);
-
}
-
}
-
}
Bellman_Ford (weights can be positive or negative) is used to judge negative rings.
1 Bellman_Frod can compute the shortest path problem with negative edge weights. It is suitable for directed and undirected graphs. It is used to solve the shortest path from source to any point.
2 In graphs with positive and negative edge weights, rings have three kinds: zero rings, positive rings and negative rings. If there are zero rings and positive rings, the path will not change after removal, and if there are negative rings, the shortest path will not exist. So since there is no negative ring, the shortest path only passes through n-1 points except the source point, so the shortest path from the source point to each point can be obtained through n-1 relaxation.
3. Time complexity o(n*m);
4 If there are rings, dis arrays can be updated after n-1 relaxation operations.
5 Template:
-
-
-
-
-
-
-
-
#define INF 0xFFFFFFF
-
#define MAXN 1010*2
-
int dis[MAXN];
-
strucu Edge{
-
int x;
-
int y;
-
int value;
-
}e[MAXN];
-
-
-
int min(int a , int b){
-
return a < b ? a : b;
-
}
-
-
-
void input(){
-
for(int i = 0 ; i < m ; i++){
-
scanf("%d%d%d" , e[i].x , &e[i].y , &e[i].value);
-
e[i+m].x = e[i].y;
-
e[i+m].y = e[i].x;
-
e[i+m].value = e[i].value;
-
}
-
}
-
-
-
void Bellman_Ford(int s){
-
-
for(int i = 1 ; i <= s ; i++)
-
dis[i] = INF;
-
dis[s] = 0;
-
for(int i = 1 ; i < n ; i++){
-
for(int j = 0 ; j < 2*m ; j++){
-
if(dis[e[j].y] > dis[e[j].x] + e[j].value)
-
dis[e[j.].y] = dis[e[i].x]+e[j].value;
-
}
-
}
-
}
-
}
-
-
-
-
-
-
-
-
#define INF 0xFFFFFFF
-
#define MAXN 1010*2
-
int dis[MAXN];
-
strucu Edge{
-
int x;
-
int y;
-
int value;
-
}e[MAXN];
-
-
-
int min(int a , int b){
-
return a < b ? a : b;
-
}
-
-
-
void input(){
-
for(int i = 0 ; i < m ; i++){
-
scanf("%d%d%d" , e[i].x , &e[i].y , &e[i].value);
-
e[i+m].x = e[i].y;
-
e[i+m].y = e[i].x;
-
e[i+m].value = e[i].value;
-
}
-
}
-
-
-
void Bellman_Ford(int s){
-
-
for(int i = 1 ; i <= s ; i++)
-
dis[i] = INF;
-
dis[s] = 0;
-
for(int i = 1 ; i < n ; i++){
-
for(int j = 0 ; j < 2*m ; j++){
-
if(dis[e[j].y] > dis[e[j].x] + e[j].value)
-
dis[e[j.].y] = dis[e[i].x]+e[j].value;
-
}
-
}
-
}
-
}
SPFA (weights can be positive or negative), judging negative rings.
1 is used to solve the shortest path of single source and the shortest path from source to any point.
2 algorithm introduction: establish a queue q, the initial queue has only one starting point, in the establishment of an array dis record starting point to all the shortest path, and initialize the array. Then the relaxation operation is carried out, using the points in the queue to refresh the starting point to all the shortest paths. If the refresh point is successful and the refresh point is no longer in the queue, the point is added to the end of the queue and repeated until the queue is empty.
3 Time Complexity: O (k e), K refers to the average number of teams entering all vertices. It can be proved that k<=2, e is the number of edges.
4. SPFA can be used to determine whether there is a ring or not. If so, the relaxation operation with one edge is greater than or equal to n.
5 Template:
-
-
-
-
-
-
-
-
#define MAXN 1010
-
#define INF 0xFFFFFFF
-
-
int n , m;
-
int first[MAXN] , next[MAXN];
-
int star[MAXN] , end[MAXN] , value[MAXN];
-
int dis[MAXN];
-
queue<int>q;
-
-
-
void input(){
-
scanf("%d%d" , &n , &m);
-
-
for(int i = 1 ; i <= n ; i++){
-
first[i] = -1;
-
next[i] = -1;
-
}
-
-
for(int i = 0 ; i < m ; i++){
-
scanf("%d%d%d" , &star[i] , &end[i] , &value[i]);
-
star[i+m] = end[i];
-
end[i+m] = star[i];
-
value[i+m] = value[i];
-
-
next[i] = first[star[i]];
-
first[star[i]] = i;
-
next[i+m] = first[star[i+m]];
-
first[star[i+m]] = i+m;
-
}
-
}
-
-
-
void SPFA(int s){
-
while(!q.empty())
-
q.pop();
-
int vis[MAXN];
-
memset(vis , 0 , sizeof(vis));
-
-
for(int i = 1 ; i <= n ; i++)
-
dis[i] = INF;
-
dis[s] = 0;
-
q.push(s);
-
vis[s] = 1;
-
while(!q.empty()){
-
int x = q.front();
-
q.pop();
-
vis[x] = 0;
-
-
for(int i = first[x] ; i != -1 ; i = next[i]){
-
if(dis[end[i]] > dis[x] + value[i]){
-
dis[end[i]] = dis[x] + value[i];
-
if(!vis[end[i]]){
-
vis[end[i]] = 1;
-
q.push(end[i]);
-
}
-
}
-
}
-
}
-
-
-
-
-
-
-
-
#define MAXN 1010
-
#define INF 0xFFFFFFF
-
-
int n , m;
-
int first[MAXN] , next[MAXN];
-
int star[MAXN] , end[MAXN] , value[MAXN];
-
int dis[MAXN];
-
queue<int>q;
-
-
-
void input(){
-
scanf("%d%d" , &n , &m);
-
-
for(int i = 1 ; i <= n ; i++){
-
first[i] = -1;
-
next[i] = -1;
-
}
-
-
for(int i = 0 ; i < m ; i++){
-
scanf("%d%d%d" , &star[i] , &end[i] , &value[i]);
-
star[i+m] = end[i];
-
end[i+m] = star[i];
-
value[i+m] = value[i];
-
-
next[i] = first[star[i]];
-
first[star[i]] = i;
-
next[i+m] = first[star[i+m]];
-
first[star[i+m]] = i+m;
-
}
-
}
-
-
-
void SPFA(int s){
-
while(!q.empty())
-
q.pop();
-
int vis[MAXN];
-
memset(vis , 0 , sizeof(vis));
-
-
for(int i = 1 ; i <= n ; i++)
-
dis[i] = INF;
-
dis[s] = 0;
-
q.push(s);
-
vis[s] = 1;
-
while(!q.empty()){
-
int x = q.front();
-
q.pop();
-
vis[x] = 0;
-
-
for(int i = first[x] ; i != -1 ; i = next[i]){
-
if(dis[end[i]] > dis[x] + value[i]){
-
dis[end[i]] = dis[x] + value[i];
-
if(!vis[end[i]]){
-
vis[end[i]] = 1;
-
q.push(end[i]);
-
}
-
}
-
}
-
}
Topics:
less