今天继续看《啊哈,算法》,学到了Floyd-Warshall算法
刚开始突然给我出现了e[i][j] 与 e[i][1]+e[1][j] 比较然后哪个小就赋值给e[i][j]
根据开头图来绘制出下面的表格,像之前求出最短路径使用深搜与广搜的方法
这一次不用深搜与广搜来解决最小路径
举个例子现在:
要求1->3的最小路径,首先看图 一种是直接到达目的地:4->3 是有12格 另一种是有中转点:4->1->3 这里路径仅有11格 如何通过Floyd-Warshall思想得到呢 我们将4->1->3 分成 4->1 和1->3 此时我们将初始点到目标点设置为i=4,j=3 4->1 指向的就是e[i][1] 1->3 指的就是 e[1][3] 这样就形成了 if(e[i][j]>(e[i][1]+e[1][j])) e[i][j] = e[i][1]+e[1][j] 里面的1就是每一行的第一位,到了这里你是否会提问为什么要1呢,2,3,4行嘛 这里其实只是举个例子,有些点可能要根据2这个中转点找到两点之间最短路径 例如上图中的1->3 就需要顶点2来求出最短路径 我们只需要用一个for(k=1;k<=n;k++) 然后加上判断语句就能全部进行判定比较,来得到最小路径 使用for的话,if(e[i][j]>(e[i][k]+e[k][j])) e[i][j] = e[i][k]+e[k][j],这里的1就要改变成k了
一定要自己亲手比对过去,才好理解,这里想说发明的人也忒聪明了,他的名字是RobertW.Floyd(罗伯特.费罗伊德)
下面上代码:
#include <stdio.h> int main() { int e[51][51]; int inf = 999999; int n,m,a,b,c,i,j,k; 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",&a,&b,&c); e[a][b] = c; } for(i=1;i<=n;i++) for(j=1;j<=n;j++) for(k=1;k<=n;k++) if(e[i][j]>(e[i][k]+e[k][j])) e[i][j]=e[i][k]+e[k][j]; for(i=1;i<=n;i++){ for(j=1;j<=n;j++) printf("%d ",e[i][j]); printf("\n"); } return 0; }
如何设置无穷大的值:
认为无穷大与其他值相加得到一个大于正无穷的数是不被允许的话加两个判断条件:
if(e[i][k]<inf && e[k][j]<inf && e[i][j]>(e[i][k]+e[k][j]))