Algorithm training shortest path (Bellman-Ford algorithm, Blue Bridge Cup C++)

The shortest test algorithm training

Resource limitation
Time limitation: 1.0s Memory limitation: 256.0MB
Problem description
Given a directed graph with n vertices and m edges (some of the edges may have negative weights, but it is guaranteed that there are no negative rings). Please calculate the shortest path from point 1 to other points (the vertices are numbered from 1 to n).

Input format
Two integers n, m in the first line.

In the next m rows, there are three integers u, v, l in each row, which means that there is an edge of length l from u to v.

The output format
has n-1 lines, and the i-th line represents the shortest path from point 1 to point i+1.
Sample input
3 3
1 2 -1
2 3 -1
3 1 2
Sample output
-1
-2
Data scale and convention
For 10% of data, n = 2, m = 2.

For 30% of the data, n <= 5 and m <= 10.

For 100% data, 1 <= n <= 20000, 1 <= m <= 200000, -10000 <= l <= 10000, to ensure that all other vertices can be reached from any vertex.

Preface: I finally learned all the methods of the shortest path QAQ

Ideas and analysis: There are 4 common methods for the shortest path. First of all, this question has negative weights . Dijkstra's algorithm cannot be used. If the data size n is 20,000 , then Flody cannot use QAQ, so let’s talk about it today. Bellman-Ford algorithm.

1. First of all, this question needs to enter the number of nodes n, the number of weighted edges m, and then the nodes on both sides of the edge and the three variables of the edge weight. The Bellmanford algorithm first needs to set up five one-dimensional arrays : store the first node The shortest path to the i-th node dist[20005], temporary array bak[20005], edge start point array u[200005], edge end point array [200005], edge weight array len[200005]
2. The idea of ​​BF is to traverse For each side, to change the shortest distance of each point, the core code is:

if(dist[v[k]]>dist[u[k]]+len[k])
{
    
      		
		dist[v[k]]=dist[u[k]]+len[k];//1号顶点到v[j]顶点的路径 > 1号顶点到u[j]的距离 + v[j]到u[j]边的权值
}

This code means that every time a weighted edge is accessed, it is judged whether the shortest path length from the first node to the end node of the edge is greater than the shortest path from the first node to the starting point of the edge plus the weight of the edge , and if so, modify it. The shortest path to the end point, visit all the weighted edges at one time, because the result will be different after each inner loop modification, so the outer loop must have n-1 times, a total of (n-1) * m times

for(int j=1;j<=n;j++)
    {
    
    
        for(int k = 1;k<=m;k++)
           if(dist[v[k]]>dist[u[k]]+len[k]){
    
      //1号顶点到v[j]顶点的路径 > 1号顶点到u[j]的距离 + v[j]到u[j]边的权值
				dist[v[k]]=dist[u[k]]+len[k];
			}
	}

3. Because the time complexity is O(n²) , when the data is large, we should also try to reduce the number of unnecessary loops. After the current large loop is executed, if the shortest path array does not move, we will end the loop, so set An array bak to store the shortest path array for each round, and check to monitor whether it has changed:

 dist[1] = 0;			//本身到本身当然路径是0
    for(int j=1;j<=n;j++)
    {
    
    
        check = 0;
        for(int i=1;i<=n;i++) bak[i]=dist[i];
        for(int k = 1;k<=m;k++)
        {
    
    
           if(dist[v[k]]>dist[u[k]]+len[k]){
    
      //1号顶点到v[j]顶点的路径 > 1号顶点到u[j]的距离 + v[j]到u[j]边的权值
				dist[v[k]]=dist[u[k]]+len[k];
			}
        }
        for(int x=1;x<=n;x++)
			//只要有不相等的说明最短路径还没算完,退出验证的循环
			if(bak[x]!=dist[x]){
    
    
				check=1;
				break;
			}

So the core algorithm is like this, the following is the complete code:

#include<bits/stdc++.h>
using namespace std;

int v[200005],u[200005],len[200005];
int dist[20005], bak[20005];


int main()
{
    
    
	int n,m;
	cin >> n>>m;
	for(int i = 1;i<=m;i++)
    {
    
    
        cin >>u[i]>>v[i]>>len[i];
    }
    int check;
    memset(dist,999999,sizeof dist);
    dist[1] = 0;
    for(int j=1;j<=n;j++)
    {
    
    
        check = 0;
        for(int i=1;i<=n;i++) bak[i]=dist[i];
        for(int k = 1;k<=m;k++)
        {
    
    
           if(dist[v[k]]>dist[u[k]]+len[k]){
    
      //1号顶点到v[j]顶点的路径 > 1号顶点到u[j]的距离 + v[j]到u[j]边的权值
				dist[v[k]]=dist[u[k]]+len[k];
			}
        }
        for(int x=1;x<=n;x++)
			//只要有不相等的说明最短路径还没算完,退出验证的循环
			if(bak[x]!=dist[x]){
    
    
				check=1;
				break;
			}
		if(check==0) break;//最短路径全部算完,退出核心算法循环
    }
    for(int i=2;i<=n;i++) printf("%d\n",dist[i]);

	return 0;
}

Afterword: At first, I used O(n³) Flody to do it (it is a brute force cracking method), only 30 minutes, 70 minutes QAQ overtime, there are 20 days to continue the school! ! !

Guess you like

Origin blog.csdn.net/Kyrie_irving_kun/article/details/113804588