| 
    
     |  | ▼うしろ さん: >以下に示すような系統図があり、それぞれ路線(root*)は延長、面積を持っています。
 >
 >rootA--rootB-+rootD-+rootH-+rootK(out)
 >       |   |   |
 >    rootC-+   |   |
 >rootE--rootF--rootG-+   |
 >              |
 >       rootI--rootJ-+
 
 
 ><したいこと>
 >起点路線から延長、面積を合計し、延長は合流点で上流側の長い延長に自分の延長を加えるようにする。
 >
 
 まだ途中ですが、
 計算順を調べるには「トポロジカル・ソート」とか
 トポロジカル・ソーティング をキーワードにして検索してみてください。
 
 [A:D]に元データが以下のようにあったとして
 [F:H]列に計算結果を表示しています。
 
 A   B   C  D    F  G  H
 路線名 接続先 延長 面積   路線名 総延長 面積
 A   B   120  10    A  120   10
 B   D    50  20    B  170   30
 C   D    60  20    C  60   20
 D   H   110  50    D  280   80
 E   F   100  40    E  100   40
 F   G    90  70    F  190  110
 G   H    70  100    G  260  210
 H   K    30  30    H  310  110
 I   J    80  80    I   80   80
 J   K    20  60    J  100  140
 K       10  70    K  320  180
 (途中まで)というのは 面積が総面積の計算になっていない、という
 ことです。ここは修正する必要があります。
 
 '--------------------------- 標準モジュール
 Option Explicit
 Public Enum VisitFlag
 NEVER = 0
 JUST
 ONCE
 End Enum
 
 Private Const N = 11
 Private Order&
 Private Rname$(1 To N)
 Private Oname$(1 To N)
 Private mat&(1 To N, 1 To N), Visited&(1 To N)
 
 Private Sub visit(i&)
 Dim j&
 Visited(i) = JUST
 For j = 1 To N
 If mat(j, i) = JUST Then
 If Visited(j) = NEVER Then
 visit j  ' ----------- 再帰して調査
 ElseIf Visited(j) = JUST Then
 MsgBox "サイクルあり", vbCritical
 Stop
 End If
 End If
 Next
 Visited(i) = ONCE
 Order = Order + 1
 Oname(Order) = Rname(i)
 End Sub
 
 Sub TopoMain()
 Dim i&, j&, v
 Dim dic As Object
 Set dic = CreateObject("Scripting.Dictionary")
 Dim upper As Object
 Set upper = CreateObject("Scripting.Dictionary")
 
 
 '// データを読む 2行目から
 v = Range("A2").Resize(N, 4).Value
 For i = 1 To N
 Rname(i) = v(i, 1)
 dic(Rname(i)) = i
 Next
 For i = 1 To N
 If Not IsEmpty(v(i, 2)) Then
 j = dic(v(i, 2))
 mat(i, j) = JUST
 End If
 Next
 
 '// ソーティング実行
 For i = 1 To N
 If Visited(i) = NEVER Then visit i
 Next
 '  計算順の表示
 Dim s As String, z As String, e
 ReDim ans(N, 1 To 3)
 ans(0, 1) = "路線名"
 ans(0, 2) = "総延長"
 ans(0, 3) = "面積"
 For i = 1 To N
 s = Oname(i)
 j = dic(s)
 If upper.Exists(v(j, 2)) Then
 upper(v(j, 2)) = upper(v(j, 2)) & "," & Rname(j)
 Else
 upper(v(j, 2)) = Rname(j)
 End If
 Debug.Print Oname(i); "("; upper(Oname(i)); ") ";
 ans(i, 1) = s
 ans(i, 2) = v(j, 3)
 ans(i, 3) = v(j, 4)
 Next
 Debug.Print
 For i = 1 To N
 dic(Oname(i)) = i
 Next
 
 ' 上の例ですと
 '   A() B(A) C() D(B,C) E() F(E) G(F) H(D,G) I() J(I) K(H,J)
 '  のようにイミディエイト・ウィンドウに表示されるはずです。
 '  ( ) のなかは 上流路線名です。
 
 
 '// 上流から計算
 Dim which As Long
 Dim tot&
 For i = 1 To N
 s = Oname(i)
 '上流を加算
 z = upper(s)
 If Len(z) Then     '上流があるとき
 If InStr(z, ",") > 0 Then '複数上流のとき
 tot = 0
 For Each e In Split(z, ",")
 j = dic(e)
 If tot < ans(j, 2) Then
 tot = ans(j, 2)
 which = j    '総延長の長いほう
 End If
 Next
 Else
 which = dic(upper(s)) '上流番号
 End If
 ans(i, 2) = ans(i, 2) + ans(which, 2)
 ans(i, 3) = ans(i, 3) + ans(which, 3)
 End If
 Next
 Range("F1").Resize(N + 1, 3).Value = ans
 
 End Sub
 
 |  |