第21講 末項確定法
第5話 末講確定法最適乱数系列探索ソフトプログラム例(後半)

void f2(int g){
  f(s==100)return;
  ow=DateTime::Now;
  TimeSpan jsa=ow->Subtract(*hj);
  if(jsa.TotalSeconds>0.01)return;
  int i,j,k,h,wa,kk,kkk,m,yy,hh,sa;
  yy=a1[y[g]][x[g]];
  array<String^>^ w=gcnew array<String^>(16);
  if(g==n-1){
    wa=0;
    for(j=0;j<n-1;j++){
      wa+=a2[j][j];
    }
    sa=n*(n-1)/2-wa;
    if(sa<0 || sa>n-1)return;
    if(p[yy][sa]==1)return;
    if(cn2[sa]>n-1)return;
    a2[y[g]][x[g]]=sa;
    p[yy][sa]=1;
    cn2[sa]++;
    f2(g+1);
    ow=DateTime::Now;
    TimeSpan jsa=ow->Subtract(*hj);
    if(jsa.TotalSeconds>0.01)return;
    cn2[sa]--;
    p[yy][sa]=0;
    return;
  }
  if(y[g]==n-1 && x[g]==0){
    wa=0;
    for(j=0;j<n-1;j++){
      wa+=a2[j][n-1-j];
    }
    sa=n*(n-1)/2-wa;
    if(sa<0 || sa>n-1)return;
    if(p[yy][sa]==1)return;
    if(cn2[sa]>n-1)return;
    a2[y[g]][x[g]]=sa;
    p[yy][sa]=1;
    cn2[sa]++;
    f2(g+1);
    ow=DateTime::Now;
    TimeSpan jsa=ow->Subtract(*hj);
    if(jsa.TotalSeconds>0.01)return;
    cn2[sa]--;
    p[yy][sa]=0;
    return;
  }
  if(y[g]==0 && x[g]==n-2){
  wa=0;
  for(j=0;j<n-2;j++){
    wa+=a2[0][j];
    }
    wa+=a2[0][n-1];
    sa=n*(n-1)/2-wa;
    if(sa<0 || sa>n-1)return;
    if(p[yy][sa]==1)return;
    if(cn2[sa]>n-1)return;
    a2[y[g]][x[g]]=sa;
    p[yy][sa]=1;
    cn2[sa]++;
    f2(g+1);
    ow=DateTime::Now;
    TimeSpan jsa=ow->Subtract(*hj);
    if(jsa.TotalSeconds>0.01)return;
    cn2[sa]--;
    p[yy][sa]=0;
    return;
  }
  if(y[g]==n-2 && x[g]==0){
    wa=0;
    for(j=0;j<n-2;j++){
      wa+=a2[j][0];
    }
    wa+=a2[n-1][0];
    sa=n*(n-1)/2-wa;
    if(sa<0 || sa>n-1)return;
    if(p[yy][sa]==1)return;
    if(cn2[sa]>n-1)return;
    a2[y[g]][x[g]]=sa;
    p[yy][sa]=1;
    cn2[sa]++;
    f2(g+1);
    ow=DateTime::Now;
    TimeSpan jsa=ow->Subtract(*hj);
    if(jsa.TotalSeconds>0.01)return;
    cn2[sa]--;
    p[yy][sa]=0;
    return;
  }
  if(y[g]>0 && y[g]<n-1 && x[g]==n-1){
    wa=0;
    for(j=0;j<n-1;j++){
      wa+=a2[y[g]][j];
    }
    sa=n*(n-1)/2-wa;
    if(sa<0 || sa>n-1)return;
    if(p[yy][sa]==1)return;
    if(cn2[sa]>n-1)return;
    a2[y[g]][x[g]]=sa;
    p[yy][sa]=1;
    cn2[sa]++;
    f2(g+1);
    ow=DateTime::Now;
    TimeSpan jsa=ow->Subtract(*hj);
    if(jsa.TotalSeconds>0.01)return;
    cn2[sa]--;
    p[yy][sa]=0;
    return;
  }
  if(x[g]>0 && x[g]<n-1 && y[g]==n-1){
    wa=0;
    for(j=0;j<n-1;j++){
      wa+=a2[j][x[g]];
    }
    sa=n*(n-1)/2-wa;
    if(sa<0 || sa>n-1)return;
    if(p[yy][sa]==1)return;
    if(cn2[sa]>n-1)return;
    a2[y[g]][x[g]]=sa;
    p[yy][sa]=1;
    cn2[sa]++;
    if(g<n*n-1){
      f2(g+1);
      ow=DateTime::Now;
      TimeSpan jsa=ow->Subtract(*hj);
      if(jsa.TotalSeconds>0.01)return;

    }
    else{
      s++;
      if(s==100)return;
    }
    cn2[sa]--;
    p[yy][sa]=0;
    return;
  }
  kk=rand()%n;
  m=n/2;
  for(i=0;i<n;i++){
    kkk=(kk+i)%n;
    a2[y[g]][x[g]]=kkk;
    h=1;
    cn2[kkk]++;
    if(cn2[kkk]>n)h=0;
    hh=0;
    if(h==1){
      if(p[yy][kkk]==0){
        p[yy][kkk]=1;
        hh=1;
      }
      else{
        h=0;
      }
    }
    if(h==1)f2(g+1);
    ow=DateTime::Now;
    TimeSpan jsa=ow->Subtract(*hj);
    if(jsa.TotalSeconds>0.01)return;
    if(hh==1)p[yy][kkk]=0;
    cn2[kkk]--;
  }
}

簡単に解説しておきましょう。
    ow=DateTime::Now;
    TimeSpan jsa=ow->Subtract(*hj);
    if(jsa.TotalSeconds>0.01)return;
f1やf2は、冒頭と上の世界から戻って来たときに入れるのが、
最も効率的に設定時間を過ぎたときに終了させるのにいいようです。
何故、戻ってきたときかと申しますと、
設定時間が過ぎているわけですから、あらゆるf1やf2をことごとく終了させたいわけです。
あらゆるf1と言い方の疑問を持たれる方のいらっしゃるかもしれませんが、
記述してあるf1は1個しかありませんが、例えばセル番号gが99までいったときには、
100個(0からはじめるので99+1)のf1が作動しています。
f2においてもg=99なら100個のf2が働いています。
つまりこのときは、計200個の関数が稼働しているのです。

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

ピンクの数字はセルに実際に張っている数字ではなくセル番号のgです。)

g=99が終了して
  if(x[g]>0 && x[g]<n-1 && y[g]==n-1){
    wa=0;
    for(j=0;j<n-1;j++){
      wa+=a2[j][x[g]];
    }
    sa=n*(n-1)/2-wa;
    if(sa<0 || sa>n-1)return;
    if(p[yy][sa]==1)return;
    if(cn2[sa]>n-1)return;
    a2[y[g]][x[g]]=sa;
    p[yy][sa]=1;
    cn2[sa]++;
    if(g<n*n-1){
      f2(g+1);
      ow=DateTime::Now;
      TimeSpan jsa=ow->Subtract(*hj);
      if(jsa.TotalSeconds>0.01)return;

    }
    else{
      s++;
      if(s==100)return;
    }
    cn2[sa]--;
    p[yy][sa]=0;
    return;
  }
によって、g=98の世界(セル)の戻ってきますが、
ここでもすぐにg=98の世界を終了させてたい訳です。
ですから、上の世界(g=99の世界)から戻ってきたらすぐに今の世界(g=98)の世界を終了させたいわけです。
  if(y[g]>0 && y[g]<n-1 && x[g]==n-1){
    wa=0;
    for(j=0;j<n-1;j++){
      wa+=a2[y[g]][j];
    }
    sa=n*(n-1)/2-wa;
    if(sa<0 || sa>n-1)return;
    if(p[yy][sa]==1)return;
    if(cn2[sa]>n-1)return;
    a2[y[g]][x[g]]=sa;
    p[yy][sa]=1;
    cn2[sa]++;
    f2(g+1);
    ow=DateTime::Now;
    TimeSpan jsa=ow->Subtract(*hj);
    if(jsa.TotalSeconds>0.01)return;

    cn2[sa]--;
    p[yy][sa]=0;
    return;
  }
そのためには、f2(g+1);の後に
      ow=DateTime::Now;
      TimeSpan jsa=ow->Subtract(*hj);
      if(jsa.TotalSeconds>0.01)return;

がなければならないわけです。
f2(g+1);の後に
      ow=DateTime::Now;
      TimeSpan jsa=ow->Subtract(*hj);
      if(jsa.TotalSeconds>0.01)return;

があれば、次々に関数f2が終了していきます。
そして、f2の100個が終了した後、
f1が次々に終了していって、すべてが終了した後にはじめて
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {
        n=int::Parse(textBox1->Text);
        s=0;
        if(n%2==1)g1(n);
        if(n%2==0)g2(n);
        for(sk=0;sk<20000;sk++){
          hj=DateTime::Now;
          syokika();
          int i;
          srand(sk);
          f1(0);
          array<String^>^ w=gcnew array<String^>(16);
          ow=DateTime::Now;
          TimeSpan jsa=ow->Subtract(*hj);
          if(s>0){
            w[6]=n.ToString();w[7]="次";w[8]=sk.ToString();w[9]=L"";w[10]=L"時";w[11]=L"間";w[12]=L"計";w[13]=L"則";w[14]=L":"; w[15]=(jsa.TotalSeconds).ToString();
            for(i=0;i<6;i++)w[i]=L"";
            dataGridView1->Rows->Add(w);
            break;
          }
          s=0;
        }
      }
の世界に戻れるのです。



第21講第4話へ 第21講第6話へ


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