Application of graphs - solving the shortest path (BFS, Dijkstra and Floyd algorithms)

Although the BFS algorithm can solve the shortest path problem, it should be noted that this algorithm can only solve the single-source shortest path problem of non-weighted graphs, or the single-source shortest path problem of graphs with the same weight and 1.

1. Definition of adjacency matrix storage structure of graph

#define MaxVerNum 100            //顶点数目的最大值 
typedef struct{
	char Vex[MaxVerNum];     //顶点表
	int Edge[MaxVerNum][MaxVerNum];    //邻接矩阵,边表
	int vexnum,archnum;              //图的当前顶点数和弧数 
}Graph;

2. Definition of adjacency list storage structure of graph

#define MaxVerNum 100            //顶点数目的最大值 
typedef struct ArcNode{           //边表结点 
	int adjvex;                  //该弧所指向的顶点的位置
	struct ArcNode *next;        //指向下一条弧的指针 
	int num;                    //图的权值 
}ArcNode; 
typedef struct VNode{           //顶点表信息 
	char data;                  //顶点信息 
	ArcNode *first;              //指向第一条依附于该顶点的弧的指针 
}VNode,AdjList[MaxVerNum];
typedef struct{
	AdjList vertices;            //邻接表
	int vexnum,arcnum;             //图的顶点数和弧数 
}Graph;

3. The BFS algorithm solves the single-source shortest path of a non-weighted graph

//BFS算法求解非带权图单源最短路径问题
void BFS_MIN_Distance(Graph G,int u)    //求到u的单源最短路径 
{
	for(int i=0;i<G.vexnum;i++)
	{
		d[i]=INF;         //初始化路径长度
		path[i]=-1;       //初始化到达每个顶点的前驱结点 
	}	
	visit[u]=true;
	d[u]=0;            //自身到自身的距离为0 
	EnQueue(Q,u);
	while(!isEmpty(Q))
	{
		DeQueue(Q,u);
		for(w=FirstNeighbor(G,u);w>=0;w=NextNeighbor(G,u,w))
		{
			if(!visit[w])
			{
				visit[w]=true;
				d[w]=d[u]+1;         //路径长度加1 
				path[w]=u;           //最短路径是从u到w 
				EnQueue(Q,w);       //w入队 
			}
		}
	}
} 

Due to the limitations of the application of the BFS algorithm, when we need to solve the single-source shortest path for a graph with a weight (positive value), we can use the Dijkstra algorithm.

The single-source shortest path refers to the shortest path from one vertex to other vertices in the graph.

4. Definition of Dijkstra algorithm 

Dijsktra algorithm is a typical single-source shortest path algorithm, which is used to calculate the shortest path from one node to all other nodes. The main feature is that the starting point is the center and expands to the outer layer until it reaches the end point. In the undirected graph G=(V,E), assuming that the length of each edge E[i] is w[i], find the shortest path from the vertex v0 to the rest of the points. 

5. The basic idea of ​​Dijkstra algorithm 

1. Generate the shortest path algorithm in increasing order of path length.

2. Divide V into two groups:

S: The set of vertices for which the shortest path has been obtained. Initially, there is only one source point in S, and each time a shortest path is obtained, it will be added to the set S until all vertices are added to S;

VS=T: the set of vertices for which the shortest path has not been determined;

3. Add the vertices in T to S in the increasing order of the shortest path, and ensure that the shortest path length from the source point V0 to each vertex in S is not greater than the shortest path length from V0 to any vertex in T.

4. Each vertex corresponds to a distance value:

Vertex in S: the shortest path length from V0 to this vertex;

Vertex in T: the length of the shortest path from V0 to this vertex that only includes the vertices in S as intermediate vertices;

6. The specific implementation process

First initialize it all to infinity (except source to source):

Select a point a with the shortest path in the table, start from a, the distance from a to itself is 0, it has three sides outside, update the shortest distance from a to b, c, d, at this time a is marked, then a will no longer be accessed, at which point the table is updated to:

Then select the shortest distance in this table, which is A->B, and select B as the new starting point. It has two sides to reach C and E respectively. Since the distance from B to C is 2, it passes from the source point The shortest distance from B to C is 3, which is smaller than before, so the shortest distance is updated, and B is also marked at this time, and B will no longer be visited.

Then choose the shortest distance in this table. From AàC, choose point C as the new starting point. There are 2 sides starting from C, reaching D and E respectively. Since the shortest distance from A to E through C is 23, it is smaller than before 51, so update the shortest distance, the shortest distance from A to D through C is 8, which is less than the previous 10, update the shortest distance, then C is marked at this time, and C will not be accessed again.

Then choose the shortest distance in this table, from A->D, so choose D as the new starting point, there is only one side from D, and reach E, then the shortest distance from A to E through B, C, D is 11 , is smaller than the previous 23, so the shortest distance is updated, then D is marked at this time, and D will no longer be visited.

Then choose the shortest distance in this table, only A->E, because it has no unvisited edges, so the loop jumps out, and the whole traversal ends!

So the single-source shortest paths for this directed graph are 0, 1, 3, 8, 11.

 When it is necessary to update the shortest path, use the array tar to record the previous vertex to the current vertex, that is, the arc tail and arc head of the best path. Then use a depth-first traversal to recursively find the shortest path from each vertex to the source.

7. Give an example of Dijkstra's algorithm for solving the single-source shortest path 

【Problem Description】

Given a non-negative weighted graph with n vertices and m directed edges, please calculate the distance from s to each point in the graph.

[Input and output and examples]

Input: the number of vertices n, the number of edges m, the source point s, and the m edges are input in the form of (p, q, weight), which respectively represent the arc tail, arc head and arc length;

Output: The distance from the source point to each point, and the path from the source point to each point.

Example 1:

Input: Vertices: 7, Edges: 10, Source: 1

      The arc tail, arc head and arc length are:

     1 2 13

      1 3 8

      1 5 30

      1 7 32

      2 6 9

      2 7 7

      3 4 5

      4 5 6

      5 6 2

      6 7 17

             

Output: The shortest path length from source to vertex 1 is: 0

      The shortest path from source to vertex 1 is: 1

      The shortest path length from source to vertex 2 is: 13

      The shortest path from source to vertex 2 is: 1 2

      The shortest path length from source to vertex 3 is: 8

      The shortest path from source to vertex 3 is: 1 3

      The shortest path length from source to vertex 4 is: 13

      The shortest path from source to vertex 4 is: 1 3 4

      The shortest path length from source to vertex 5 is: 19

      The shortest path from source to vertex 5 is: 1 3 4 5

      The shortest path length from source to vertex 6 is: 21

      The shortest path from source to vertex 6 is: 1 3 4 5 6

      The shortest path length from source to vertex 7 is: 20

      The shortest path from source to vertex 7 is: 1 2 7

 code:

#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
#define INF 0X3F3F3F3F

//使用链式存储边,建图 
struct node{
	int begin;  //边的始点 
	int end;    //边的终点 
	int cost;   //边的代价 
	int next;   //当前边的下一条相邻边 
}e[1010]; 

int head[1010];   //head[i]存储与该点相邻的边
int dis[1010];    //存放源点到每个点的最短距离 
int visit[1010];  //标记哪些点被访问,访问的点被设为1 
int tar[1010];    //追踪最短路径

void dfs(int s,int v)   //输出最短路径 
{
	if(s==v)    //递归到源点,输出源点 
	{
		cout<<s<<" ";
		return ;
	}
	dfs(s,tar[v]);     //一直寻找到达该点的路径 
	cout<<v<<" ";
} 
int main()
{
	int n,m,s;
	cout<<"请输入顶点的个数、边的条数以及源点的位置: ";
	cin>>n>>m>>s;
	cout<<"请输入每条边的起点、始点和代价:"<<endl;
	for(int i=1;i<=m;i++)   //存储边,建图 
	{
		cin>>e[i].begin>>e[i].end>>e[i].cost;
		int from=e[i].begin;     //记录当前是从哪个点发出 
		e[i].next=head[from];    //存储该点的下一条边 
		head[from]=i;           // 更新与该点的相邻的最后一条边(也就是当前边) 
	} 
	
	for(int i=1;i<=n;i++)  //初始化,先将每个距离设置为最大值 
	{
		dis[i]=INF;
	} 
	
	int begin=s;
	dis[begin]=0;   //自己到自己的最短距离为0 
	
	while(visit[begin]!=1)  //对每个点进行查找,直至所有点被标记完 
	{
		visit[begin]=1;   //没被访问,那就访问 
		for(int i=head[begin];i!=0;i=e[i].next)  //依次访问与当前起点相邻的边
		{
			if(dis[e[i].end]>dis[e[i].begin]+e[i].cost)  //更新不同起点到达该点的最短距离 
			{
				dis[e[i].end]=dis[e[i].begin]+e[i].cost;
				tar[e[i].end]=e[i].begin;   //存储当前点的前一个点 
			}
		} 
		
		int min1=INF;
		for(int i=1;i<=n;i++)   //每一次都寻找所有还没被标记的点中距离最小的点
		{
			if(visit[i]!=1&&dis[i]<min1)
			{
				min1=dis[i];
				begin=i;   //以距离最小的点为新的起点,从当前点出发 
			}
		}
	} 
	
	cout<<"源点到每个点的最短路径长度:"<<endl;
	for(int i=1;i<=n;i++) 
	{
		cout<<"源点到顶点"<<i<<"的最短路径长度为:"<<dis[i]<<endl;
		if(dis[i]==INF)   //说明不可达
		{
			cout<<"该点不可达!"<<endl<<endl;
		} 
		else
		{
			cout<<"源点到顶点"<<i<<"的最短路径是:";
			dfs(s,i);
			cout<<endl<<endl;
		}
	}
	return 0;
}

It should be noted that although the Dijkstra algorithm can solve the single-source shortest path problem with weighted graphs, its weights can only be non-negative values. For negative weights, the algorithm may not be able to obtain correct results. 

8. Floyd algorithm to find the shortest path between vertices 

The Floyd algorithm is actually based on the idea of ​​dynamic programming. It tries to add vertex k as an intermediate vertex in the original path, and compares the length of the new path obtained with the original path to obtain the shortest path.

#define Maxsize 100
int path[Maxsize][Maxsize];       //记录某一顶点到另一顶点的中转矩阵
int A[Maxsize][Maxsize];          //记录从顶点i到顶点j的路径长度 
//初始化准备工作,初始化矩阵A和path 
for(int k=0;k<n;k++)     //列举中转点 
{
	for(int i=0;i<n;i++)    //遍历整个矩阵的行和列 
	{
		for(int j=0;j<n;j++)
		{
			if(A[i][j]>A[i][k]+A[k][j])
			{
				A[i][j]=A[i][k]+A[k][j];    //更新最短路径 
				path[i][j]=k;              //记录中转点 
			}
		}
	}
}

The time complexity of Floyd's algorithm is O(|V|^3), and the space complexity is O(|V|^2). This algorithm can solve the problem with negative weights in the graph, but it does not allow loops composed of edges with negative weights, because such graphs may not have the shortest path. 

Guess you like

Origin blog.csdn.net/m0_51769031/article/details/125364334