|
楼主 |
发表于 2012-12-31 19:02
|
显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用 · 内置多项VBA编程加强工具 ★ 免费下载 ★ ★ 使用手册★
FLoyd-Warshall算法的正确实现
本帖最后由 lee1892 于 2013-1-4 15:02 编辑
FLoydWarshall的正确实现
由于1楼提到的帖子里虽然描述了弗洛伊德算法,但实际上却没有正确的用代码实现,所以另写了一个放在1楼的附件集里了。
这个算法的思维逻辑是:
最外层的 k 是扫描的顶点,内两层的 i 和 j 则是扫描的由 i 顶点到 j 顶点的路径(可能是数个边,也可能不通),如果 由 i 到 k 的路径 加上 由 k 到 j 的路径 的总长(或花费)小于由 i 到 j 的长度,则用后两者合并来取代原先的路径。
1楼附件的申明部分如下,注意保存路径部分的代码比较麻烦,实际上合并两个数组后取代,或则用字典对象或集合对象会比数组方便:
[code=vb]
Private Type VERTEX_INFO
Name As String ' 顶点名称
End Type
Private Type EDGE_INFO
FromVertex As Long ' 起点地址
ToVertex As Long ' 终点地址
Length As Double ' 边的长度
End Type
Private Type PASS_INFO
Length As Double
Vertex() As Long ' 所经过的数组
End Type
Private aVertexes() As VERTEX_INFO ' 顶点数组
Private cVertexHash As Collection ' 集合模拟散列表,用名称索引顶点数组下标
Private aEdges() As EDGE_INFO ' 边数组
Private aFloydTable() As PASS_INFO ' 结果矩阵,保存了图中任意两点的最短路径信息
Private dInfinite As Double ' 定义无穷大为全部边长度之和
[/code]
这里采用了顶点集合和边集合分开的方式,以便该算法的使用。另外构造了一个FloydTable用来保存结果,这是一个二维矩阵,行序号对应起点,列序号对应终点。可以看到,对于无向图而言,上下半区是对称的。
算法实现的代码如下:
[code=vb]
Private Sub FloydWarshall()
Dim i&, j&, k&, nVertNum&, n&
nVertNum = UBound(aVertexes)
ReDim aFloydTable(1 To nVertNum, 1 To nVertNum)
For i = 1 To nVertNum
For j = 1 To nVertNum
With aFloydTable(i, j)
.Length = dInfinite
ReDim .Vertex(0 To 0)
If i = j Then .Length = 0
End With
Next
Next
For i = 1 To UBound(aEdges)
With aEdges(i)
aFloydTable(.FromVertex, .ToVertex).Length = .Length
End With
Next
For k = 1 To nVertNum
For i = 1 To nVertNum
For j = 1 To nVertNum
With aFloydTable(i, j)
If aFloydTable(i, k).Length + aFloydTable(k, j).Length < .Length Then
.Length = aFloydTable(i, k).Length + aFloydTable(k, j).Length
' 保存新的路径,用新的经过 k 的路径替代原先的路径
ReDim .Vertex(0 To UBound(aFloydTable(i, k).Vertex) + _
UBound(aFloydTable(k, j).Vertex) + 1)
For n = 1 To UBound(aFloydTable(i, k).Vertex)
.Vertex(n) = aFloydTable(i, k).Vertex(n)
Next
.Vertex(n) = k
For n = n + 1 To UBound(aFloydTable(k, j).Vertex) + n
.Vertex(n) = aFloydTable(k, j).Vertex(n - UBound(aFloydTable(i, k).Vertex) - 1)
Next
End If
End With
Next
Next
Next
End Sub
[/code]
|
|