[collection does not get lost] search and fundamentals of graph theory

Keywords: data structure Graph Theory dijkstra kruskal Prim

catalogue

🌠DFS

🌠BFS

🌠 Breadth first traversal of trees and graphs

→ topological sorting

Example:

🌠 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)

πŸ’‘ Similarities and differences between Bellman Ford and Dijkstra

❓ Why can't Dijkstra be used in graphs with negative weights and Bellman Ford can?  

Example:

​

→ SPFA (queue optimization for Bellman Ford) (it is required that the figure does not contain negative rings)

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

[DFS template question] Full Permutation and n-queen problem_ β˜† confused dog's secret base β˜† - CSDN blog directory arranges numbers using one-dimensional array mark and binary mark n-queen problem. Understanding of key operations arranges numbers input example: 3 output example: 1 2 31 3 22 1 32 3 13 1 23 2 1 uses one-dimensional array mark #include < iostream > using namespace STD; const int N = 10; int n,path[N]; bool b[N]; void dfs(int m){ if(m == n){..https://blog.csdn.net/qq_39391544/article/details/120616653

Β 

🌠BFS

[BFS template question] Array version / STL version and recording route β˜† secret base of confused dog β˜† - CSDN blog directory title. Use array to simulate queue. Use queue to expand: input example of recording route Title: 5 50 1 0 00 00 1 0 0 0 00 1 1 1 1 1 00 00 0 10 output example: 8 use array to simulate queue # include < iostream > #include < CString > #include < algorithm > using namespace STD; const int n = 110 ..https://blog.csdn.net/qq_39391544/article/details/120631009

Β 

🌠 Breadth first traversal of trees and graphs

[array simulation] AcWing 847. Hierarchy at the point of the figure β˜† secret base of confused dog β˜† - CSDN bloghttps://blog.csdn.net/qq_39391544/article/details/120977766

→ 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)

[summary] single source shortest path (simple Dijkstra) and minimum spanning tree (Prim,Kruskal) β˜† secret base of confused dog β˜† - CSDN bloghttps://blog.csdn.net/qq_39391544/article/details/121000591

→ 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

Dijkstrabellman-ford
withSimilar 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 πŸ‘‡  

AcWing 853. Shortest path with edge limit - AcWingAcWing, problem solution, shortest path with edge limit,https://www.acwing.com/solution/content/6320/

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

851. spfa finding the shortest path - AcWing question bank high quality algorithm question bankhttps://www.acwing.com/problem/content/853/

Β 

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;
}

Β 

🌠 Minimum spanning tree (Prim,Kruskal)

[summary] single source shortest path (naive Dijkstra) and minimum spanning tree (Prim,Kruskal) β˜† secret base of confused dog β˜† - CSDN blog naive Dijkstra time complexity: O (N2 + m), n represents the number of points, M represents the number of edges, dense graph???? storage form: adjacency matrix template: g[x][y] stores the edge weight during initialization, dist[i] The shortest distance from 1 to I is stored, that is, our goal is to find the shortest path of 1 - > n. 1. Initialization distance dist[1] = 0, d[i] = + ∞ 2.for i 1~n: t ← the nearest point s ← t that is not in the set shttps://blog.csdn.net/qq_39391544/article/details/121000591

Posted by stringfield on Sun, 31 Oct 2021 10:03:57 -0700