最短路径-Floyd-Warshall算法

在求最短路时,通过深搜和宽搜可以解决,但是使用Floyd-Warshall会有更高的效率

只用五行代码求最短路径!!!

案例:a城市到b城市有许多公路,有些城市则没有,为了节约经费,求出a到b的最短路程
以下为例,两地路程用邻接矩阵表示
在这里插入图片描述
试想通过以往的经验,如果任意两点(例如顶点a到顶点b)之间的距离路程缩短,只能引入第三个点(顶点k)并通过k中转即a→k→b,才能缩短a到b的路程,那么中转1~n的哪一个点呢?甚至有时候不止通过一个点,而是经过两个点或者多个点让路程变得更短。

下面我们来将这个问题优化:

假如允许经过1号顶点时,只需要判断e[i][1]+e[1][i]是否比e[i][j]要小即可,代码实现代码实现:

for(int i=1;i<=n;i++){
		for(int j=1j<=n;j++){
			if(e[i][1]+e[1][j]<e[i][j]){
				e[i][j]=e[i][1]+e[1][j];
			}
		}
	}

任意两点之间最短路程更新为:
在这里插入图片描述

在允许经过1和2号顶点情况下,代码实现如下:

//经过1号顶点时 
	for(int i=1;i<=n;i++){
		for(int j=1j<=n;j++){
			if(e[i][1]+e[1][j]<e[i][j]){
				e[i][j]=e[i][1]+e[1][j];
			}
		}
	}
	//经过2号顶点时 
	for(int i=1;i<=n;i++){
		for(int j=1j<=n;j++){
			if(e[i][2]+e[2][j]<e[i][j]){
				e[i][j]=e[2][1]+e[2][j];
			}
		}
	}

在允许经过1和2号顶点情况下,任意两点之间最短;路程更新为:
在这里插入图片描述
在允许经过1和2、3号顶点情况下,任意两点之间最短路程更新为:
在这里插入图片描述
最后允许所有点中转,最短路程更新为:
在这里插入图片描述
代码实现:

for(int k=1;k<=n;k++){
		for(int i=1;i<=n;i++){
		    for(int j=1j<=n;j++){
		    	if(e[i][k]+e[k][j]<e[i][j]){
			    	e[i][j]=e[i][k]+e[k][j];
		    	}
	    	}
    	}
	} 

这段代码的基本思想是:最开始允许经过1号顶点进行,求任意两点最短距离中转,接下来只允许经过2号顶点进行中转…允许1~n号顶点进行中转
用一句话概括就是:从i号顶点到j号顶点只经过前k号顶点的最短路径,其实是一种动态规划的思想

完整代码:

#include<cstdio>
int e[201][201],n,m,t1,t2,t3,a,b;
int main(){
	scanf("%d %d %d %d",&n,&m,&a,&b);
	//初始化矩阵 
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(i==j){
				e[i][j]=0;
			}else{
				e[i][j]=99999999;
			}
		}
		//读入边 
		for(int i=1;i<=m;i++){
			scanf("%d %d %d",&t1,&t2,&t3);
			e[t1][t2]=t3;
		}
	}
	//Floyd-Warshall算法核心代码 
	for(int k=1;k<=n;k++){
		for(int i=1;i<=n;i++){
		    for(int j=1;j<=n;j++){
		    	if(e[i][k]+e[k][j]<e[i][j]){
			    	e[i][j]=e[i][k]+e[k][j];
		    	}
	    	}
    	}
	} 
	 
	printf("%d\n",e[a][b]);
	
	return 0;
} 

注意:-Floyd-Warshall算法可以处理带有负权边(边的值为负数)的图,
但不能处理带有负权回路(或者叫“负权环”)的图

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章