虽然笔者在“算法-图论”的专栏中已经讨论过有关最短路径的问题,但是这里还是重新讨论一下,孔子也说过嘛,温故而知新。
所谓最短路径问题,就是基于一个图G<V、E>,图的边集E是带权的,然后讨论寻求某条连通两个点的路径,使得这条路径是所有连通该路径中边权最小的。
找到任意两点间的最短路径——Floyd-Warshall算法。
这个算法是个本科念文学后来转计算机并于1978年荣获图灵奖的Robert W.Floyd和Stephen Warshall于1962同时独立开发出来的,因此为了纪念他们,该算法融合了两个人的名字。
其实这个算法说来思路也非常简单,我们当前想要求得G中vi到vj的最短路径,最简单暴力的方法是找到vi到vj所有可走的路径,然后维护一个最小值即可。然而现在问题是如何找到这所有的路径?我们找一个中间变量k,vi->vj的路径可以分解成vi->vk 、vk->vj的路径,而将k遍历[i,j]便可枚举出所有情况,你可能会问那vi->vk还有很多路径呢,那岂不还要继续找?事实上,我们设置e[i][j]记录vi->vj的最短路径,而vi->vk、vk->vj则也是基于e[i][k]、e[k][j]的,这样我们其实是枚举了一系列相对最优的情况,然后找到这些相对最优解中的当前最优解的情况,这便是动态规划思想所体现的地方。
本质上讲,该算法是枚举和动态规划的一个巧妙的结合。
#include<cstdio> using namespace std; int main() { int e[10][10] , k , i , j , n , m , t1,t2,t3; int inf = 9999999; scanf("%d%d",&n,&m); for(i = 1;i<=n;i++) for(j = 1;j<=n;j++) if(i == j) e[i][j] = 0; else e[i][j] = inf; for(i = 1;i<=m;i++) { scanf("%d%d%d",&t1,&t2,&t3); e[t1][t2] = t3; } for(k=1;k<=n;k++) for(i=1;i<=n;i++) for(j=1;j<=n;j++) if(e[i][j] > e[i][k] + e[k][j]) //Floyd-Warshall算法的核心部分 e[i][j] = e[i][k] + e[k][j]; for(i=1;i<=n;i++) { for(j = 1;j<=n;j++) printf("%10d",e[i][j]); printf("\n"); } return 0; }
时间: 2024-11-03 20:49:45