脑文家
Floyed求多源最短路
算法过程
1,从任意一条单边路径开始。所有两点之间的距离是边的权,如果两点之间没有边相连,则权为无穷大。
2,对于每一对顶点 u 和 v,看看是否存在一个顶点 w 使得从 u 到 w 再到 v 比已知的路径更短。如果是更新它。
采用松弛技术(松弛操作),对在i和j之间的所有其他点进行一次松弛。所以时间复杂度为O(n^3);
- for(int k = 1; k <= n; k++)
- for(int i = 1; i <= n; i++)
- for(int j = 1; j <= n; j++)
- if(map[i][j] > map[i][k] + map[k][j])
- map[i][j] = map[i][k] + map[k][j];
下面给出传递闭包的定义
有向图的传递闭包表达的就是每个顶点之间的可达性。
其实朴素的Floyd传递闭包就是求两点的可达性
使用Floyd是并不是因为它复杂度低。。
而是因为它比较好写。。。
常数小。。。
- for(int k=1;k<=n;k++)
- for(int i=1;i<=n;i++)
- for(int j=1;j<=n;j++)
- 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 点的最短路径所以肯定可以遍历到最小的环;
- int map[MAXS][MAXS], dis[MAXS][MAXS];
- // 返回值为最小环权值。
- int Floyd(int n)
- {
- int minCircle = INF; // 改进后的Floyd可求最小环。 minCircle用于记录最小环权值。
- for(int k = 0; k < n; k ++)
- {
- // 改进部分 求最小环权值。
- for(int i = 0; i < k; i ++)
- for(int j = 0; j < i;j ++)
- minCircle = min(minCircle, dis[i][j] + map[i][k] + map[k][j]);
- // 通常部分。
- for(int i = 0; i < n; i ++)
- for(int j = 0; j < i; j ++)
- if(dis[i][j] > dis[i][k] + dis[k][j])
- dis[i][j] = dis[j][i] = dis[i][k] + dis[k][j];
- }
- return minCircle;
- }