最終講 卒業研究と卒業試験

第3話 課題2 9次ラテン方陣の作成

前話の課題の解答例
Public Class Form1
   '変数の宣言と初期化
   Dim a(3, 3) As Integer, x(9) As Integer, y(9) As Integer, s As Integer
   Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
     Dim ss as Integer
     s = 0
     DataGridView1.Rows.Clear()
     h()
     f(0)

     DataGridView1.Rows.Add() '1行追加
     '見出し表示
     ss = Int(s /3)
     DataGridView1(7,4 * (ss + 1)).Value() = "順"
     DataGridView1(8,4 * (ss + 1)).Value() = "列"
     DataGridView1(9,4 * (ss + 1)).Value() = "方"
     DataGridView1(10,4 * (ss + 1)).Value() = "陣"
     DataGridView1(11,4 * (ss + 1)).Value() = "総"
     DataGridView1(12,4 * (ss + 1)).Value() = "数"
     '総数表示
     DataGridView1(13,4 * (ss + 1)).Value() = s

   End Sub

   Sub h()
     For i = 0 To 8
       x(i) = i Mod 3
       y(i) = Int(i / 3)
     Next
   End Sub

   Sub f(ByVal g As Integer)
     If s = 100 Then Exit Sub  '計算時間が膨大なので100個で止めている。
     
Dim h, sa, ss As Integer

     For i = 0 To 8
       a(y(g), x(g)) = i + 1
       h = 1
       If g > 0 Then
         For j = 0 To g - 1
           If a(y(j), x(j)) = a(y(g), x(g)) Then
             h = 0
             Exit For
           End If
         Next
       End If
       If h = 1 Then
         If g + 1 < 9 Then
           f(g + 1)
         Else
           sa = s Mod 3
            ss = Int(s / 3)
           For j = 0 To 2
             If sa = 0 Then DataGridView1.Rows.Add() '1行追加
             For k = 0 To 2
               DataGridView1(k + 4 * sa, j + 4 * ss).Value = a(j, k)
             Next
           Next
           If sa = 0 Then DataGridView1.Rows.Add() '1行追加
           s = s + 1 '総数カウント
           If s = 100 Then Exit Sub  '計算時間が膨大なので100個で止めている。
         
End If
       End If
     Next

   End Sub

End Class


VBAでは、Dim h, sa, ss As Integerにように宣言することが出来ませんので、
勘違いしていましたが、VB2010ではそのように宣言して問題がないことが、
わかりました。どのバージョンからまとめて宣言できるようになったかは知りませんが、
VC++に対抗するためにそう変えたのではないでしょうか。
ずっとだめだと思っていましたが、C言語のように
w = w + a

w += a
と簡略表現が許されています。


さらに、改良して計算時間が計測できるように変更したいと思います。
時刻を収納する変数はDateTime型です。したがいまして、
Dim 変数名 As DateTime
と宣言されます。
現在時刻はNowで取得できます。
例えば、時刻を収納する変数をhjとすれば、
hj = Now
です。
計算を始める前に現在の時刻を取得し、計算終了後にもう一度現在時刻を取得し、
2つの時刻差を秒単位で示せばいいことになります。
ですから、現在時刻を取得するDateTime型の変数は2つ用意しなければなりません。
そして、時刻差を収納する変数はTimeSpan型です。
ですから、変数宣言部分では
Dim hj, ow As DateTime, sa As TimeSpan, ss As Integer
などとしておきましょう。
尚、時刻差を収納する変数saを秒に変換するときは、sa.TotalSecondsとします。
では、コーティングを考えてみてください。
解答例は、例によって30行下。


































Public Class Form1
   '変数の宣言と初期化
   Dim a(3, 3) As Integer, x(9) As Integer, y(9) As Integer, s As Integer
   Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
     Dim hj, ow As DateTime, sa As TimeSpan, ss As Integer
     hj = Now
     s = 0
     DataGridView1.Rows.Clear()
     h()
     f(0)
     ss = Int(s / 3)
     DataGridView1.Rows.Add() '1行追加
     DataGridView1(7, 4 * (ss + 1)).Value() = "順"
     DataGridView1(8, 4 * (ss + 1)).Value() = "列"
     DataGridView1(9, 4 * (ss + 1)).Value() = "方"
     DataGridView1(10, 4 * (ss + 1)).Value() = "陣"
     DataGridView1(11, 4 * (ss + 1)).Value() = "総"
     DataGridView1(12, 4 * (ss + 1)).Value() = "数"
     DataGridView1(13, 4 * (ss + 1)).Value() = s '総数表示
     ow = Now
     sa = ow - hj
     DataGridView1(9, 4 * (ss + 1) + 1).Value() = "計"
     DataGridView1(10, 4 * (ss + 1) + 1).Value() = "測"
     DataGridView1(11, 4 * (ss + 1) + 1).Value() = "時"
     DataGridView1(12, 4 * (ss + 1) + 1).Value() = "間"
     DataGridView1(13, 4 * (ss + 1) + 1).Value() = sa.TotalSeconds '計測時間表示

   End Sub
            ・
            ・
            ・
実行例




さて、9次ラテン方陣の解答例を示しましょう。
Public Class Form1
   '変数の宣言と初期化
   Dim a(9, 9) As Integer, x(81) As Integer, y(81) As Integer, s As Integer
   Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
     Dim hj, ow As DateTime, sa As TimeSpan
     hj = Now
     s = 0
     DataGridView1.Rows.Clear()
     h()
     f(0)
     DataGridView1.Rows.Add() '1行追加
     DataGridView1(7, 10 * s).Value() = "順"
     DataGridView1(8, 10 * s).Value() = "列"
     DataGridView1(9, 10 * s).Value() = "方"
     DataGridView1(10, 10 * s).Value() = "陣"
     DataGridView1(11, 10 * s).Value() = "総"
     DataGridView1(12, 10 * s).Value() = "数"
     DataGridView1(13, 10 * s).Value() = s '総数表示
     ow = Now
     sa = ow - hj
     DataGridView1.Rows.Add() '1行追加
     DataGridView1(9, 10 * s + 1).Value() = "計"
     DataGridView1(10, 10 * s + 1).Value() = "測"
     DataGridView1(11, 10 * s + 1).Value() = "時"
     DataGridView1(12, 10 * s + 1).Value() = "間"
     DataGridView1(13, 10 * s + 1).Value() = sa.TotalSeconds '計測時間表示
   End Sub

   Sub h()
     For i = 0 To 80
       x(i) = i Mod 9
       y(i) = Int(i / 9)
     Next
   End Sub

   Sub f(ByVal g As Integer)
     If s = 100 Then Exit Sub
     Dim h As Integer

     For i = 0 To 8
       a(y(g), x(g)) = i + 1
       h = 1
       If x(g) > 0 Then
         For j = 0 To x(g) - 1
           If a(y(g), x(g)) = a(y(g), j) Then
             h = 0
             Exit For
           End If
         Next
       End If
       If h = 1 Then
         If y(g) > 0 Then
           For j = 0 To y(g) - 1
             If a(y(g), x(g)) = a(j, x(g)) Then
               h = 0
               Exit For
             End If
           Next
         End If
       End If

       If h = 1 Then
          If g + 1 < 81 Then
            f(g + 1)
          Else
            For j = 0 To 8
              DataGridView1.Rows.Add() '1行追加
              For k = 0 To 8
                DataGridView1(k, j + 10 * s).Value = a(j, k)
              Next
            Next
            DataGridView1.Rows.Add() '1行追加
            s = s + 1
            If s = 100 Then Exit Sub
          End If
       End If
     Next
   End Sub

End Class

実行例

変更点は、で示されています。配列の次数を変更し、
       If g > 0 Then
         For j = 0 To g - 1
           If a(y(j), x(j)) = a(y(g), x(g)) Then
             h = 0
             Exit For
           End If
         Next
       End If

       If x(g) > 0 Then
         For j = 0 To x(g) - 1
           If a(y(g), x(g)) = a(y(g), j) Then
             h = 0
             Exit For
           End If
         Next
       End If
       If h = 1 Then
         If y(g) > 0 Then
           For j = 0 To y(g) - 1
             If a(y(g), x(g)) = a(j, x(g)) Then
               h = 0
               Exit For
             End If
           Next
         End If
       End If

と変わっています。課題1では、行列の中に同じ数字が入ってはいけないという条件だったのに対して、
ラテン方陣では、行または列の中のみに同じ数字が入ってはいけないという条件だからです。
行または列に同じ数字が入らなければ、行列の中に同じ数字が入ってもよいのです。

前半
       If x(g) > 0 Then
         For j = 0 To x(g) - 1
           If a(y(g), x(g)) = a(y(g), j) Then
             h = 0
             Exit For
           End If
         Next
       End If
       

で行のチェックをしています。
後半
       If h = 1 Then
         If y(g) > 0 Then
           For j = 0 To y(g) - 1
             If a(y(g), x(g)) = a(j, x(g)) Then
               h = 0
               Exit For
             End If
           Next
         End If
       End If

で列のチェック



同じものがあるとh = 0 となり、
       If h = 1 Then
          If g + 1 < 81 Then
            f(g + 1)
          Else
            For j = 0 To 8
              DataGridView1.Rows.Add() '1行追加
              For k = 0 To 8
                DataGridView1(k, j + 10 * s).Value = a(j, k)
              Next
            Next
            DataGridView1.Rows.Add() '1行追加
            s = s + 1
            If s = 100 Then Exit Sub
          End If
       End If

が実行ず、ループが次に進むようになっています。
尚、皆さんFor i = 0 To 89If g + 1 < 81 Thenの81に注意して下さい。
行や列に入る数字(セルの内容)は1から9まで(a(y(g), x(g)) = i + 1  + 1があるので0から8は1から9までとなる)
であるのに対して、セル番号は0から80までです。
繰り返しますが、セル番号(セルのラベル)とセルの内容(セルに入る1から9までの数字)は明確に区別しないといけません。
明瞭に区別していないと、プログラムは訳のわからないものとなります。




さて、皆さん課題3
課題2に条件
C ブロックの数字が重複してはならない。
を付け加えてください。
に挑戦しましょう。


第2話へ 第4話へ

006

VC++講義第1部へ
vb講義へ
VB講義基礎へ
初心者のための世界で一番わかりやすいVisual C++入門基礎講座

数学研究室に戻る