floyd这个东西学会了好久了,但是原理总是忘记,或者说没有真正的明白,这里在说一下。
我们要求的是任意的 i,j 之间的最短路径,用动态规划的思想来解决就是f[i,j,k]表示i到j中间节点不超过k的最短路径,那么分两种情况讨论:
case1:经过k,如果经过k,很显然f[i,j,k]=f[i,k,k-1]+f[k,j,k-1]; 由动态规划的一些性质可以知道,这样是无后效性的;
case2:不经过k,那么很简单,f[i,j,k]=f[i,j,k-1];
发现这两个方程中至于k-1有关,这样便可以省去一维空间,变成f[i,j]=max(f[i,j],f[i,k]+f[k,j]);
至于k,只需要迭代就可以了。
————————————————————————————————————————————————————————————————
floyd求最小环:
先来贴个代码:
1 int mincircle = infinity; 2 Dist = Graph; 3 for(int k=0;k<nVertex;++k){ 4 //新增部分: 5 for(int i=0;i<k;++i) 6 for(int j=0;j<i;++j) 7 mincircle = min(mincircle,Dist[i][j]+Graph[j][k]+Graph[k][i]); 8 //通常的 floyd 部分: 9 for(int i=0;i<nVertex;++i) 10 for(int j=0;j<i;++j){ 11 int temp = Dist[i][k] + Disk[k][j]; 12 if(temp < Dist[i][j]) 13 Dist[i][j] = Dist[j][i] = temp; 14 } 15 }
大家可以先仔细看看这代码
发现了吗?只是在普通的floyd基础上又进行了了一个找环操作。相信大家仔细琢磨能琢磨出个大概意思,不顾我要在这里解释2个难理解的地方
1、为什么新增部分放在第K次最短路前面
【最小环的一个算法】令e(u,v)表示u和v之间的连边,再令min(u,v)表示,删除u和v之间的连边之后,u和v之间的最短路最小环则是min(u,v) + e(u,v)
Floyd中的k用来作为每节点进行最短路的更新min(u,v)路过K点,由于k是0~n,如果我们按照k值作为环节点的最大值,则可以取环【名叫第k层环】
dist存两点间的最短距离,g存放原图距离那么第k环的最小环
min= g[l~k]+g[k~r]+dist[l][r] 其中0<l<r<k
其中对dist[l][r]的要求是dist没有经过点值大于k的点的优化。
【反例】如果求第k层环的最小环时 dist有进过k点优化过,那么可能产生dist[l][r]=g[l][k]+g[k][r]
那么结果就变成:min=2*(g[l][k]+g[k][r]) 很明显这只是对一条路径的来回走动,而非环所以第k层环的最小
所以k层环应该要在求 dist有路由k点之前求出!
【结论】k层环的最小环 = g[l~k] + g[k~r] + dist[l][r] {0<l<r<k(dist为k-1层环时候更新的最短路)
2、为什么不能在原数组上直接操作而要两个数组?(一般的floyd都在一个数组上操作)
原因很简单,和第一个问题一样,如果在原数组上操作,就会有dist在前面被优化过,会产生1中的【反例】