第3講 第2講の魔方陣を高速化しよう!

第2話 新しいセル位置番号付けはどうするか?

n = 3 のとき

n = 4 のとき

 0  1  2  3
 0  8  9  4
10  1  5 12
11  6  2 14
  13 15  3

n = 5 のとき

 0  1  2  3  4
 0  9 10 11  5
12  1 15  6 16
13 17  2 19 20
14  7 21  3 23
 8 18 22 24  4

n = 6 のとき

 0  1  2  3    5
 0 12 13 14 15  6
16  1 20 21   22
17 23  2  8 26 27
18 24  9  3 30 31
19 10 28 32  4 34
11 25 29 33 35  5


1次元であるセル位置番号gと2次元添え字(i,j)を1:1に対応させるにはどうしたらよいでしょうか。
i = iz(g)  j = jz(g)としましょう。
かなり複雑ですが次のようにプログラムすると一般化できます。
(一般化の意味は、6次までに限定されず、例えば100次でも199次でも成り立つという意味です。)

奇数次の場合
Sub zahyouk()
  For i = 0 To n * n - 1
    If i < n Then
      iz(i) = i
      jz(i) = i
    End If
    If i >= n And i < 2 * n - 1 Then
      iz(i) = i - n
      jz(i) = 2 * n - i - 1
      If iz(i) >= jz(i) Then
        iz(i) = iz(i) + 1
        jz(i) = jz(i) - 1
      End If
    End If

    m = Int(n / 2)

    For j = 1 To m

      aj = -j * j + (4 * m + 1) * j + 1
      If i >= aj And i < aj + n - 1 - j Then
        iz(i) = j - 1
        jz(i) = i - aj + j
        If jz(i) >= n - j Then jz(i) = jz(i) + 1
      End If

      bj = -j * j + 4 * m * j + 2 * m + 1
      If i >= bj And i < bj + n - 1 - j Then
        iz(i) = i - bj + j
        jz(i) = j - 1
        If iz(i) >= n - j Then iz(i) = iz(i) + 1
      End If

      cj = -j * j + (2 * m + 3) * j + 3 * m * m + m - 1
      If i >= cj And i < cj + m + 1 - j Then
        iz(i) = m + j - 1
        jz(i) = i - cj + m + j
      End If

      dj = -j * j + (2 * m + 2) * j + 3 * m * m + 2 * m
      If i >= dj And i < dj + m + 1 + j Then
        iz(i) = i - dj + m + j
        jz(i) = m + j - 1
      End If
    Next
  Next
End Sub

偶数次の場合

Sub zahyoug()
  For i = 0 To n * n - 1
    If i < n Then
      iz(i) = i
      jz(i) = i
    End If
    If i >= n And i < 2 * n Then
      iz(i) = i - n
      jz(i) = 2 * n - i - 1
    End If
    m = Int(n / 2)
    w = m - 1

    For j = 1 To m
      aj = -j * j + (4 * w + 3) * j + 2
      If i >= aj And i < aj + n - 1 - j Then
        iz(i) = j - 1
        jz(i) = i - aj + j
        If jz(i) >= n - j Then jz(i) = jz(i) + 1
      End If
    Next

    For j = 1 To m
      bj = -j * j + (4 * w + 2) * j + 2 * w + 3
      If i >= bj And i < bj + n - 1 - j Then
        jz(i) = j - 1
        iz(i) = i - bj + j
        If iz(i) >= n - j Then iz(i) = iz(i) + 1
      End If
    Next

    For j = 1 To m - 1
      cj = -j * j + (3 + 2 * w) * j + 3 * w * w + 5 * w + 2
      If i >= cj And i < cj + m - j Then
        iz(i) = j + w
        jz(i) = i - cj + m + j
      End If
    Next

    For j = 1 To m - 1
      dj = -j * j + (2 * w + 2) * j + 3 * w * w + 6 * w + 3
      If i >= dj And i < dj + m - j Then
        jz(i) = j + w
        iz(i) = i - dj + m + j
      End If
    Next
  Next
End Sub

今回は大変複雑なプログラムです。
階差数列の和をつかって、分析して以上のようにプログラムしたわけです。

実際、番号2次元添え字対応表プログラム
を実行してみると例えば10次では

0 1 2 3 4 5 6 7 8 9 10
0 0 21 22 23 24 25 26 27 28 29 11
1 30 1 39 40 41 42 43 44 45 12 46
2 31 47 2 55 56 57 58 59 13 60 61
3 32 48 62 3 69 70 71 14 72 73 74
4 33 49 63 75 4 81 15 82 83 84 85
5 34 50 64 76 86 5 91 92 93 94 95
6 35 51 65 77 16 96 6 101 102 103 104
7 36 52 66 17 87 97 105 7 109 110 111
8 37 53 18 78 88 98 106 112 8 115 116
9 38 19 67 79 89 99 107 113 117 9 119
10  20  54  68  80  90 100 108 114 118 120 10

となっていてgとi、jの関係に普遍性があることがわかります。
しかし、かなり難解なプログラムであることは認めざるを得ません。
次回で詳しく解説したいと思います。
また、表示のプログラムソースを示しておくと、
Sub hyouji()
  Dim i As Integer
  iti = iti + n + 1

  For i = 0 To n * n - 1
    Cells(iti + iz(i) + 2, 2 + jz(i)) = i
  Next
  For i = 0 To n - 1
    Cells(iti + 1, i + 2).Select
    With Selection.Font
      .ColorIndex = 7
    End With
    Cells(iti + 1, i + 2) = i
  Next
  For i = 0 To n - 1
    Cells(iti + i + 2, 1).Select
    With Selection.Font
      .ColorIndex = 3
    End With
    Cells(iti + i + 2, 1) = i
  Next
  Cells(2, 1).Select
End Sub
です。
Cells(iti + iz(i) + 2, 2 + jz(i)) = i
のitiについては後でまた説明しますが、
表示行位置調整のためのものです。




第3講第1話へ
 第3講第3話へ


VB入門講義応用編トップへ

VB入門講義トップへ