第18講 一般種法×末項確定法(魔方陣作成マクロVer.4)への挑戦
第15話 最適値自動探索プログラムの実験結果による最適値とそれによる改良
12次については、現在実験中です。
試行回数の設定が50000では結果が出なかったので、
100000に設定し直して実験しています。
実験結果が出るのに半日かかるので、それを待つしかありませんので、
12次については明日以降と言うことになります。
試行回数とは、プログラムコードの
If sk > 3000 Then Exit Sub
のskです。下の実験結果をご覧になればお分かりのように、6次までなら設定値は50で済むことになります。
この設定値を大きくすると時間がかかりますので、次数に応じて設定値を変更する必要があります。
11次までの実験結果をお見せしましょう。
次数 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
最小試行回数 | 0 | 5 | 48 | 178 | 373 | 1109 | 9802 | 11752 | |
最適シード値 | 6763 | 6601 | 5084 | 9362 | 6337 | 5104 | 1763 | 436 | |
最適素な数1 | 1 | 3 | 5 | 3 | 1 | 4 | 9 | 6 | |
最適素な数2 | 3 | 1 | 1 | 3 | 3 | 1 | 9 | 6 |
尚、9〜11次においては実験を途中で打ち切ったので、for文は10000までは試していません。
For c = 1 To 10000
h = 0
kz = 0
If n = 4 Then kk =
1
If n = 5 Then kk = 3
If n = 6 Then kk = 1
If n = 7 Then
kk = 5
If n = 8 Then kk = 3
If n = 9 Then kk = 5
If n = 10
Then kk = 3
If n = 11 Then kk = 10
If n = 12 Then kk =
3
For d = 0 To kk
For e = 0 To
kk
syokika
Randomize (c)
ms1 (0)
If
cn = 1 Then h = 1
Next
Next
If h = 1
Then
Cells(6 + kz2, 1) = c
kz2 = kz2 + 1
End If
Next
10次からは、for文のどこまで進行したか表示するようにプログラムを変更しましたが、
その値を見るのを忘れて次の実験に入ってしまいましたので、
いくつまでの実験結果は報告できません。11次は9000ぐらいで打ち切りました。
11次はほぼ最後まで実験しましたから、最小試行回数は1万回程度でしょうが、
9次と10次に関しては、表の値より小さい可能性があります。
実験結果で驚きは、6次までの最小試行回数です。
4次に至っては、最適シード値と最適素な数による結果はなんと0です。
ということは、ストレートに4次魔方陣ができたということです。
試行回数0、適当に入れていったら行ったり来たりせず一発で答えが出てしまったわけです。
これはかなりの幸運といえます。
最適素な数1 と 最適素な数2 とは、下のコードの iii = (ii + ss * i) Mod n のssです。
何と素な関係にあるかと申しますと、nとです。
例えば、n=10のときは、nと素な数は1,3,7,9です。
10と素な数とは、10と共通の約数が1である数です。
ssが素な数である場合 iii = (ii + ss * i) Mod n はすべての場合を網羅します。
n=10,ss=3,ii=6でトレースしてみましょう。
iを0から9まで変えていくと、
iii=(6+3*0) Mod 10=6
iii=(6+3*1) Mod 10=9
iii=(6+3*2) Mod 10=2
iii=(6+3*3) Mod 10=5
iii=(6+3*4) Mod 10=8
iii=(6+3*5) Mod 10=1
iii=(6+3*6) Mod 10=4
iii=(6+3*7) Mod 10=7
iii=(6+3*8) Mod 10=0
iii=(6+3*9) Mod 10=3
6,9,2,5,8,1,4,7,0,3と0から9まで確かにすべて重複なしに網羅しています。
しかも、現れ方はかなりランダムのように見えます(実際は3飛びに規則的)。
皆さん、10と素な関係にない4などでトレースしてみてください。
すると、重複なしに網羅していないことがわかります。
10と素な数でない2,4,5,6,8はすべて重複なしに網羅するの条件を満たしません。
実験結果によるVer.4の改良コードをお見せします。
改良部分を紺で示しておきます。
Dim mah1(12, 12) As Byte, mah2(12, 12) As Byte, x(144) As Byte, y(144) As Byte, p1(144) As Byte, p2(144) As Byte, a(12, 12) As Integer
Dim th(12, 12) As Byte
Dim n As Byte, cn As Integer, gk As Integer, tm As Byte
Private Sub CommandButton1_Click()
Dim i, j As Integer
n = Cells(3, 8)
syokika
zhy
zhy1 (0)
'zhykakunin
syokika1
ms1 (0)
End Sub
Sub syokika()
Dim i As Byte
Dim j As Byte
For i = 0 To n - 1
p1(i) = 0
p2(i) = 0
For j = 0 To n - 1
th(i, j) = 0
Next
Next
tm = 0
sk = 0
cn = 0
gk = n
For i = 0 To n - 1
For j = 0 To n - 1
a(i, j) = -1
Next
Next
End Sub
Sub syokika1()
Dim i As Byte
Dim j As Byte
For i = 0 To n - 1
For j = 0 To n - 1
mah1(i, j) = 0
mah2(i, j) = 0
Next
Next
Rnd (-1)
If n = 4 Then Randomize (6763)
If n = 5 Then Randomize (6601)
If n = 6 Then Randomize (5084)
If n = 7 Then Randomize (9362)
If n = 8 Then Randomize (6337)
If n = 9 Then Randomize (5104)
If n = 10 Then Randomize (1763)
If n = 11 Then Randomize (436)
End Sub
Sub zhy()
Dim i As Byte
For i = 0 To n - 1
a(i, i) = i
Next
For i = 0 To n - 1
If a(i, n - 1 - i) = -1 Then
a(i, n - 1 - i) = gk
gk = gk + 1
End If
Next
End Sub
Sub zhy1(g As Byte)
Dim i As Byte
For i = g + 1 To n - 1
If a(g, i) = -1 Then
a(g, i) = gk
gk = gk + 1
End If
Next
zhy2 (g)
If tm = 1 Then Exit Sub
End Sub
Sub zhy2(g As Byte)
Dim i As Byte
Dim j As Byte
For i = g + 1 To n - 1
If a(i, g) = -1 Then
a(i, g) = gk
gk = gk + 1
End If
Next
If g + 1 < n Then
zhy1 (g + 1)
If tm = 1 Then Exit Sub
Else
For i = 0 To n - 1
For j = 0 To n - 1
y(a(i, j)) = i
x(a(i, j)) = j
Next
Next
tm = 1
Exit Sub
End If
End Sub
Sub zhykakunin()
Dim i As Byte
For i = 0 To n * n - 1
Cells(5 + y(i), 1 + x(i)) = i
Next
End Sub
Sub ms1(g As Byte)
Dim i As Integer, j As Byte, k As Byte, a As Byte, b As Byte, w As Integer, sa As Integer, h As Byte
Dim ii As Integer, iii As Integer, kk As Byte
a = x(g)
b = y(g)
If a = n - 1 And b = n - 1 Then
w = 0
For i = 0 To n - 2
w = w + mah1(i, i)
Next
sa = Int(n * (n - 1) / 2) - w
If sa < 0 Or sa > (n - 1) Then Exit Sub
If p1(sa) >= n Then Exit Sub
mah1(b, a) = sa
p1(sa) = p1(sa) + 1
ms1 (g + 1)
p1(sa) = p1(sa) - 1
Exit Sub
End If
If a = 0 And b = n - 1 Then
w = 0
For i = 0 To n - 2
w = w + mah1(i, n - 1 - i)
Next
sa = Int(n * (n - 1) / 2) - w
If sa < 0 Or sa > (n - 1) Then Exit Sub
If p1(sa) >= n Then Exit Sub
mah1(b, a) = sa
p1(sa) = p1(sa) + 1
ms1 (g + 1)
p1(sa) = p1(sa) - 1
Exit Sub
End If
If a = n - 2 And b = 0 Then
w = 0
For i = 0 To n - 3
w = w + mah1(b, i)
Next
w = w + mah1(b, n - 1)
sa = Int(n * (n - 1) / 2) - w
If sa < 0 Or sa > (n - 1) Then Exit Sub
If p1(sa) >= n Then Exit Sub
mah1(b, a) = sa
p1(sa) = p1(sa) + 1
ms1 (g + 1)
p1(sa) = p1(sa) - 1
Exit Sub
End If
If a = 0 And b = n - 2 Then
w = 0
For i = 0 To n - 3
w = w + mah1(i, a)
Next
w = w + mah1(n - 1, a)
sa = Int(n * (n - 1) / 2) - w
If sa < 0 Or sa > (n - 1) Then Exit Sub
If p1(sa) >= n Then Exit Sub
mah1(b, a) = sa
p1(sa) = p1(sa) + 1
ms1 (g + 1)
p1(sa) = p1(sa) - 1
Exit Sub
End If
If a = n - 1 And b > 0 And b < n - 1 Then
w = 0
For i = 0 To n - 2
w = w + mah1(b, i)
Next
sa = Int(n * (n - 1) / 2) - w
If sa < 0 Or sa > (n - 1) Then Exit Sub
If p1(sa) >= n Then Exit Sub
mah1(b, a) = sa
p1(sa) = p1(sa) + 1
ms1 (g + 1)
p1(sa) = p1(sa) - 1
Exit Sub
End If
If a > 0 And a < n - 1 And b = n - 1 Then
w = 0
For i = 0 To n - 2
w = w + mah1(i, a)
Next
sa = Int(n * (n - 1) / 2) - w
If sa < 0 Or sa > (n - 1) Then Exit Sub
If p1(sa) >= n Then Exit Sub
mah1(b, a) = sa
p1(sa) = p1(sa) + 1
If g + 1 < n * n Then
ms1 (g + 1)
Else
ms2 (0)
End If
p1(sa) = p1(sa) - 1
Exit Sub
End If
ii = n * Rnd
Dim ss As Byte
If n = 4 Then ss = 1
If n = 5 Then ss = 3
If n = 6 Then ss = 5
If n = 7 Then ss = 3
If n = 8 Then ss = 1
If n = 9 Then ss = 4
If n = 10 Then ss = 9
If n = 11 Then ss = 6
For i = 0 To n - 1
iii = (ii + ss * i) Mod n
mah1(b, a) = iii
h = 0
If p1(mah1(b, a)) >= n Then GoTo tobi
p1(mah1(b, a)) = p1(mah1(b, a)) + 1
h = 1
ms1 (g + 1)
tobi:
If h = 1 Then p1(mah1(b, a)) = p1(mah1(b, a)) - 1
Next
End Sub
Sub ms2(g As Byte)
Dim i As Integer, j As Byte, k As Byte, a As Byte, b As Byte, w As Integer, sa As Integer, h As Byte
Dim ii As Integer, iii As Integer, kk As Byte, hs As Integer
a = x(g)
b = y(g)
hs = mah1(b, a)
If a = n - 1 And b = n - 1 Then
w = 0
For i = 0 To n - 2
w = w + mah2(i, i)
Next
sa = Int(n * (n - 1) / 2) - w
If sa < 0 Or sa > (n - 1) Then Exit Sub
If th(mah1(b, a), sa) = 1 Then Exit Sub
If p2(sa) >= n Then Exit Sub
mah2(b, a) = sa
p2(sa) = p2(sa) + 1
th(mah1(b, a), mah2(b, a)) = 1
ms2 (g + 1)
p2(sa) = p2(sa) - 1
th(mah1(b, a), mah2(b, a)) = 0
Exit Sub
End If
If a = 0 And b = n - 1 Then
w = 0
For i = 0 To n - 2
w = w + mah2(i, n - 1 - i)
Next
sa = Int(n * (n - 1) / 2) - w
If sa < 0 Or sa > (n - 1) Then Exit Sub
If th(mah1(b, a), sa) = 1 Then Exit Sub
If p2(sa) >= n Then Exit Sub
mah2(b, a) = sa
p2(sa) = p2(sa) + 1
th(mah1(b, a), mah2(b, a)) = 1
ms2 (g + 1)
p2(sa) = p2(sa) - 1
th(mah1(b, a), mah2(b, a)) = 0
Exit Sub
End If
If a = n - 2 And b = 0 Then
w = 0
For i = 0 To n - 3
w = w + mah2(b, i)
Next
w = w + mah2(b, n - 1)
sa = Int(n * (n - 1) / 2) - w
If sa < 0 Or sa > (n - 1) Then Exit Sub
If th(mah1(b, a), sa) = 1 Then Exit Sub
If p2(sa) >= n Then Exit Sub
mah2(b, a) = sa
p2(sa) = p2(sa) + 1
th(mah1(b, a), mah2(b, a)) = 1
ms2 (g + 1)
p2(sa) = p2(sa) - 1
th(mah1(b, a), mah2(b, a)) = 0
Exit Sub
End If
If a = 0 And b = n - 2 Then
w = 0
For i = 0 To n - 3
w = w + mah2(i, a)
Next
w = w + mah2(n - 1, a)
sa = Int(n * (n - 1) / 2) - w
If sa < 0 Or sa > (n - 1) Then Exit Sub
If th(mah1(b, a), sa) = 1 Then Exit Sub
If p2(sa) >= n Then Exit Sub
mah2(b, a) = sa
p2(sa) = p2(sa) + 1
th(mah1(b, a), mah2(b, a)) = 1
ms2 (g + 1)
p2(sa) = p2(sa) - 1
th(mah1(b, a), mah2(b, a)) = 0
Exit Sub
End If
If a = n - 1 And b > 0 And b < n - 1 Then
w = 0
For i = 0 To n - 2
w = w + mah2(b, i)
Next
sa = Int(n * (n - 1) / 2) - w
If sa < 0 Or sa > (n - 1) Then Exit Sub
If th(mah1(b, a), sa) = 1 Then Exit Sub
If p2(sa) >= n Then Exit Sub
mah2(b, a) = sa
p2(sa) = p2(sa) + 1
th(mah1(b, a), mah2(b, a)) = 1
ms2 (g + 1)
p2(sa) = p2(sa) - 1
th(mah1(b, a), mah2(b, a)) = 0
Exit Sub
End If
If a > 0 And a < n - 1 And b = n - 1 Then
w = 0
For i = 0 To n - 2
w = w + mah2(i, a)
Next
sa = Int(n * (n - 1) / 2) - w
If sa < 0 Or sa > (n - 1) Then Exit Sub
If th(mah1(b, a), sa) = 1 Then Exit Sub
If p2(sa) >= n Then Exit Sub
mah2(b, a) = sa
p2(sa) = p2(sa) + 1
th(mah1(b, a), mah2(b, a)) = 1
If g + 1 < n * n Then
ms2 (g + 1)
Else
For j = 0 To n - 1
For k = 0 To n - 1
Cells(6 + k + Int(cn / 10) * (n + 1), 1 + j + (cn Mod 10) * (n + 1)) = n * mah1(j, k) + mah2(j, k) + 1
Next
Next
cn = cn + 1
Cells(4, 12) = cn
End If
p2(sa) = p2(sa) - 1
th(mah1(b, a), mah2(b, a)) = 0
Exit Sub
End If
ii = n * Rnd
Dim ss As Byte
If n = 4 Then ss = 3
If n = 5 Then ss = 1
If n = 6 Then ss = 1
If n = 7 Then ss = 3
If n = 8 Then ss = 3
If n = 9 Then ss = 1
If n = 10 Then ss = 9
If n = 11 Then ss = 6
For i = 0 To n - 1
iii = (ii + ss * i) Mod n
mah2(b, a) = iii
h = 0
If p2(mah2(b, a)) >= n Then GoTo tobi
If th(mah1(b, a), mah2(b, a)) = 1 Then GoTo tobi
p2(mah2(b, a)) = p2(mah2(b, a)) + 1
th(mah1(b, a), mah2(b, a)) = 1
h = 1
ms2 (g + 1)
tobi:
If h = 1 Then
p2(mah2(b, a)) = p2(mah2(b, a)) - 1
th(mah1(b, a), mah2(b, a)) = 0
End If
Next
End Sub
Private Sub CommandButton2_Click()
Rows("5:2000").Select
Selection.ClearContents
Cells(4, 12).Select
Selection.ClearContents
Cells(1, 1).Select
End Sub
ダウンロード用ファイルをクリックして、改良によってとても速くなったことを体感して下さい。
さて、皆さん時間を計測できるようにさらに改善しましょう。
第14話へ 第16話へ
VBA講義第1部へ
vc++講義へ
vb講義へ
VB講義基礎へ
初心者のための世界で一番わかりやすいVisual C++入門基礎講座へ
初心者のための世界で一番わかりやすいVisual Basic入門基礎講座へ
数学研究室に戻る