Floyd基础知识 多源最短路 && 传递闭包(内含优化) && 最小环

来源:互联网 发布:淘宝客是怎么推广的 编辑:程序博客网 时间:2024/06/05 16:26

脑文家

Floyed求多源最短路

算法过程
1,从任意一条单边路径开始。所有两点之间的距离是边的权,如果两点之间没有边相连,则权为无穷大。
2,对于每一对顶点 u 和 v,看看是否存在一个顶点 w 使得从 u 到 w 再到 v 比已知的路径更短。如果是更新它。
采用松弛技术(松弛操作),对在i和j之间的所有其他点进行一次松弛。所以时间复杂度为O(n^3);

[cpp] view plain copy print?
  1. for(int k = 1; k <= n; k++)  
  2.     for(int i = 1; i <= n; i++)  
  3.         for(int j = 1; j <= n; j++)  
  4.             if(map[i][j] > map[i][k] + map[k][j])  
  5.                 map[i][j] = map[i][k] + map[k][j];  


Floyed求传递闭包

     下面给出传递闭包的定义


有向图的传递闭包表达的就是每个顶点之间的可达性。

其实朴素的Floyd传递闭包就是求两点的可达性

使用Floyd是并不是因为它复杂度低。。
而是因为它比较好写。。。
常数小。。。

[cpp] view plain copy print?
  1. for(int k=1;k<=n;k++)  
  2.     for(int i=1;i<=n;i++)  
  3.         for(int j=1;j<=n;j++)  
  4.             map[i][j] = map[i][j]|(map[i][k]&map[k][j]);  

对应裸题:POJ3660 Cow Contest:http://blog.csdn.net/wzw1376124061/article/details/69870097


由于传递闭包的时间复杂度为n^3,那么当数据n=1000的时候会超时,这时可以想到用bitset优化,这时用bitset优化后的Floyd求传递闭包的时间复杂度将变成n^3/64

(64位的机子下)  这样将可以成功。

对应裸题:POJ3275 Ranking the Cows :http://blog.csdn.net/wzw1376124061/article/details/77679566


Floyed求最小环

主要过程:

Floyd 算法是按照顶点的编号增加的顺序更新最短路径的,如果存在最小环,则会在这个环中的点编号最大的那个点 k 更新最短路径之前发现这个环, 即当点u被拿来更新i到j的最短路径的时候,可以发现这个闭合环路,发现的方法是,更新最短路径前有   dist[i][j] + map[i][k] + map[k][j] != inf    这时 s 的 i 和 j 是当前环中挨着点u的两个点; 因为在之前的最短路径更新过程中, k 没有参与更新,所以 dist[i][j] 所表示的路径中不会有点 k ,即一定为一个环; 如果在每个新的点拿来更新最短路径之前遍历i和j验证上面的式子,虽然不能遍历到所有的环; 但是由于 dist[i][j] 是 i 到 j 点的最短路径所以肯定可以遍历到最小的环;

[cpp] view plain copy print?
  1. int map[MAXS][MAXS], dis[MAXS][MAXS];  
  2. // 返回值为最小环权值。  
  3. int Floyd(int n)  
  4. {  
  5.     int minCircle = INF; // 改进后的Floyd可求最小环。 minCircle用于记录最小环权值。  
  6.     for(int k = 0; k < n; k ++)  
  7.     {  
  8.         // 改进部分 求最小环权值。  
  9.         for(int i = 0; i < k; i ++)  
  10.             for(int j = 0; j < i;j ++)  
  11.                 minCircle = min(minCircle, dis[i][j] + map[i][k] + map[k][j]);  
  12.         // 通常部分。  
  13.         for(int i = 0; i < n; i ++)  
  14.             for(int j = 0; j < i; j ++)  
  15.                 if(dis[i][j] > dis[i][k] + dis[k][j])  
  16.                     dis[i][j] = dis[j][i] = dis[i][k] + dis[k][j];  
  17.     }  
  18.     return minCircle;  
  19. }  
对应裸题:洛谷P2738 [USACO4.1]篱笆回路Fence Loops:http://blog.csdn.net/wzw1376124061/article/details/71272017
原创粉丝点击