一、floyd算法求任意两点之间的最短路(实质上是动态规划):
算法原理:i、j 两点间的最短路径只有两种情况:直接从 i 到 j 或者通过中转点。
设map[i][j][k]表示从 i 到 j ,以 0—— k 号点作为中转点所能得到的最大值。以 0 作为中转点就表示 i 直接到j,不通过其他点中转点;可以从1到k号点钟选取若干点作为中转点,也可以直接不选取任何点作为中转点。
那么状态转移方程如下:
map[i][j][k]=min{map[i][j][k],map[i][k][k-1]+map[k][j][k-1]}
(看了这个递推式,或许也明白为什么floyd三重循环要将 k 放在最外面了吧)
具体代码实现:
<span style="font-size:18px;">初始map[i][j][0]为边(i,j)的值,若i与j不连通,则初始值按题意确定。
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
map[i][j][k]=min(map[i][j][k],map[i][k][k-1]+map[k][j][k-1]);</span>
观察上述代码,我们发现有几点可以改进的地方:
1.对于map数组,我们可以省略 k ,只用一个二维数组即可,即:map[i][j]
2.若 i 与 k 相同,后面就没必要枚举了,因为 i 如果与 k 相同,那么就变成不通过中转点的情况了,而这种情况在初始时就已经处理过了。
3.若是求最短路,那么 i 与 j 不相连通时,我们一般都将其权值赋值为一个极大值,map[i][k]+map[k][j]就有可能超过数据范围,继而变成一个负数,这样就出错了,解决办法就是将上述的加法变成减法。
最终代码:
<span style="font-size:18px;">初始map[i][j]的值为边(i,j)的值,若边(i,j)不存在,
则按照题意进行赋值,比如求最短路时,就赋值为一个极大值
for(k=-1;k<=n;k++)
for(i=1;i<=n;i++)if(i!=k)
for(j=1;j<=n;j++)if(j!=i && j!=k)
if(map[i][j]-map[i][k]>map[k][j])
map[i][j]=map[i][k]+map[k][j];
</span>
二、floyd求任意两点间的最短路径并输出:
设w[i][j]记录 i 与 j 是否有边相连,d[i][j]=k,表示从 i 到 j 的最短路径,i 的下一个点为 k,则有:
<span style="font-size:18px;">初始map[i][j]的值为边(i,j)的值,若边(i,j)不存在,
则按照题意进行赋值,比如求最短路时,就赋值为一个极大值
若边(i,j)存在,则初始p[i][j]的值为j,否则就为-1
for(k=-1;k<=n;k++)
for(i=1;i<=n;i++)if(i!=k)
for(j=1;j<=n;j++)if(j!=i && j!=k)
if(map[i][j]-map[i][k]>=map[k][j])
{
map[i][j]=map[i][k]+map[k][j];
if(w[i][k])d[i][j]=k;
}
</span>
接下来,若要输出(i,j)的最短路径,直接输出 i ,然后输出 k1=d[i][j],然后输出 k2=d[k1][j],以此内推。
三、floyd寻找环:
用w[i][j]记录边(i,j)的值,假设存在一个如下的环:
map[i][j][k-1]
i ———————— j
↘ ↙
↘ ↙
↘ ↙
k
若map[i][j][k-1]==w[i][j]+w[k][j],则存在一个环。
对于求环的算法,要灵活使用,比如求最大环,最小环,环的最大、最小权值等等。
鉴于此,这里就不给出代码了,相关例题可以去我的博客查找,我的每篇文章后面都是注明了使用算法以及求解问题的,找起来还是比较方便(当然,没有的话,额。。。。,那就这样吧)