天天看点

floyd算法详解

一、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],则存在一个环。

       对于求环的算法,要灵活使用,比如求最大环,最小环,环的最大、最小权值等等。

       鉴于此,这里就不给出代码了,相关例题可以去我的博客查找,我的每篇文章后面都是注明了使用算法以及求解问题的,找起来还是比较方便(当然,没有的话,额。。。。,那就这样吧)

继续阅读