第16講 関数の再帰的呼び出しによる3次・4次魔方陣の作成
第3話 小改良と実験

解説に入る前にプログラムに少し改良を加えておきましょう。
一つ目の改良は、時間を計測できるようにすることです。
2つ目は、魔方陣を一定数作ったらプログラムを停止させるようにすることです。
VBAの場合は、魔方陣が1個できる度にエクセルのシートにリアルタイムで表示させることができますが、
DataGridViewやLabelは、すべての計算が終了した後にしか表示できない仕様になっているからです。
現在のままなら、4次魔方陣7040個を作らせるにも20分もかかしましますし、
5次魔方陣約21億個なら100年コンピュータを走らせても計算は終わらないでしょう。
これからいろいろ改良を加えていって、魔方陣作成速度が1万倍、10万倍、100万倍と伸びていきますが、
それでも5次でさえ、何年も待たないと結果は出てきませんし、
6次以上なら数千年待っても結果は出てこないでしょう。

一つ目の改良は、
DateTime^ hj=DateTime::Now;
n=int::Parse(textBox1->Text);
s=0;
f(0);
int i;
array<String^>^ x=gcnew array<String^>(16);
x[9]=L"魔";x[10]=L"方";x[11]=L"陣";x[12]=L"総";x[13]=L"数";x[14]=L":";x[15]=s.ToString();
for(i=0;i<9;i++)x[i]=L"";
dataGridView1->Rows->Add(x);
DateTime^ ow=DateTime::Now;
TimeSpan sa=ow->Subtract(*hj);
x[10]=L"時";x[11]=L"間";x[12]=L"計";x[13]=L"則";x[14]=L":";x[15]=(sa.TotalSeconds).ToString();
for(i=0;i<10;i++)x[i]=L"";
dataGridView1->Rows->Add(x);

のようにピンクを加えます。時間計測については、
第12講7話並び替え第3の方法の改良の試みで解説していますのでそちらを参考にして頂きたいと思いますが、
ここでも簡単に解説しておきましょう。
DateTime^ hj=DateTime::Now;ではDateTime^型の変数hjを宣言し現在の時間つまりは初めの時間で初期化(初めの時間を代入)しています。
同じくDateTime^ ow=DateTime::Now;ではDateTime^型の変数owを宣言し現在の時間つまりは終わりの時間で初期化(終わりの時間を代入)しています。
TimeSpan sa=ow->Subtract(*hj);では時間差を計測するTimeSpan型の変数を宣言するとともに時間差を計算し代入しています。
sa=ow->Subtract(*hj)はDateTime^型で宣言したときはそう書くのだと暗記して頂くしかありません。
変数hjとowを『DateTime hj』『DateTime ow』と^マークをつけない形で宣言しておけばよりシンプルなsa=ow-hjになります。


2つ目の改良は、関数fの方で、
void f(char g){
  if(s==10)return;
  int i,j,k,h,x,y,xx,yy,wa;
          .
          .
          .
        if(h==1){
          if(g<n*n-1){
            f(g+1);
          }
          else{
            for(j=0;j<n;j++){
              for(k=0;k<n;k++){
                 w[k]=(a[j][k]).ToString();
              }
              dataGridView1->Rows->Add(w);
            }
            for(j=0;j<16;j++)w[j]=L"";
            dataGridView1->Rows->Add(w);
            s++;
            if(s==10)return;
          }
          .
           .
           .
とします。これは10個できたら停止させてSystem::Void button1_Clickに戻るようにさせた場合です。これなら4次魔方陣でも
と3秒程度で結果が出てきます。
尚、計測時間はもちろんパソコンのスペックによって変わります。ここに出ているのは私のパソコンによるものです。
もし100個計測したいならif(s==10)return;if(s==100)return;と変更します。


最初の10個作るのに約3秒、100個作るには約15秒と個数に比例しないのは、最初の1個を作るに相当時間が掛かるからです。
試しif(s==1)return;にとして実験してみましょう。

つまり最初の1個作るのに0.76秒もかかっているのです。
この1個を除いて作成に掛かった時間を計算してみると、
(3.576−0.7644)÷9=0.3124
(15.3504−0.7644)÷99=0.147333
です。
最初の1個を除けば、ほぼ個数に比例するの予想のもとに記述を進めていたのですが、
予想が外れてしまいました。
ですが、これはデータ数が少なすぎるからだと思われます。そこで、if(s==200)return; if(s==300)return; if(s==400)return;
などとして実験し改めて計算してみましょう。



(35.2092−0.7644)÷199=0.173089
(50.232−0.7644)÷299=0.165443
(68.8116−0.7644)÷399=0.170554
これなたら予想通りです。
1個目は0.7644秒、2個目以降は平均で約0.17秒です。皆さんも実験してみて下さい。

ソースの解説は次話以降で行います。
皆さんが理解できるように詳しく説明していきます。
乞うご期待!


第11講第6話へ
 第12講第1話へ 第14講第10話へ 第15講第10話へ 第16講第2話へ 第16講第4話へ


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