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

第2話 課題1 順列を2次元に並べる

課題1は前に作った順列作成ソフトを少し改良すれば出来ます。
9次順列を2次元に並べるだけです。

セルの内容 
セル番号 


0 1 2
3 4 5
6 7 8

下のコーティングのgはセル番号に対応しています。
順列のときと同じでセルのラベル(すなわちセル番号)であるとセルに入っている数字(セルの内容)を区別しないと訳がわからなくなります。


初心者入門
ビール瓶で例えれば、『一番搾り』がラベルで、内容が『ビール』でしたね。
セル番号(セルのラベル)と内容(1から9までの行列を構成する数字)を明確に区別して下さい。
上図の右側のiはfor(i=0;i<9;i++)のiに対応し、gはvoid f(char g)のgです。
このgは0から8へと進んでいきます。

0 1 2
3 4 5
6 7 8

次のコーティング例は、この課題だけとしては少し難しいかもしれませんが、
最終的には数独(ナンバープレイス)解答作成が目的ですから、
それとの関連を考えてのことです。

コーティング例
#pragma once
int a[3][3];
int x[9],y[9];
int s;
namespace 順列方陣 {

  using namespace System;  
        ・
        ・
        ・
#pragma endregion
  private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {
           s=0;
           h();
           f(0);
           dataGridView1->Rows->Add();
           dataGridView1[8,4*s]->Value=L"順";
           dataGridView1[9,4*s]->Value=L"列";
           dataGridView1[10,4*s]->Value=L"方";
           dataGridView1[11,4*s]->Value=L"陣";
           dataGridView1[12,4*s]->Value=L"数";
           dataGridView1[13,4*s]->Value=s.ToString();
        }
        void h(){
           char i;
           for(i=0;i<9;i++){
             x[i]=i%3;
             y[i]=i/3;
           }
        }
        void f(char g){
           if(s==100)return;  'すべて計算させるとかなり時間がかかるので100個で止めている。
           int i,j,k,h;
           for(i=0;i<9;i++){
             a[y[g]][x[g]]=i+1;
             h=1;
              if(g>0){
               for(j=0;j<g;j++){
                 if(a[y[g]][x[g]]==a[y[j]][x[j]]){
                   h=0;
                   break;
                 }
               }
             }

             if(h==1){
               if(g+1<9){
                 f(g+1);
               }
              else{
                for(j=0;j<3;j++){
                  dataGridView1->Rows->Add();
                    for(k=0;k<3;k++){
                      dataGridView1[k,j+4*s]->Value=a[j][k];                      
                    }
                  }
                  dataGridView1->Rows->Add();
                  s++;
                }
              }
             }
        }

  };
}
実行例
基礎

解説
           dataGridView1->Rows->Add();
           dataGridView1[8,4*s]->Value=L"順";
           dataGridView1[9,4*s]->Value=L"列";
           dataGridView1[10,4*s]->Value=L"方";
           dataGridView1[11,4*s]->Value=L"陣";
           dataGridView1[12,4*s]->Value=L"数";
           dataGridView1[13,4*s]->Value=s.ToString();       
ここは、次のようにしても同じ結果が得られます。
           array<String^>^ w=gcnew array<String^>(14);
           w[8]=L"順";w[9]=L"列";w[10]=L"総";w[11]=L"数";w[12]=L":";w[13]=s.ToString();
           dataGridView1->Rows->Add(w);
array<String^>^ w=gcnew array<String^>(14);はString^型で要素数14の配列を宣言しています。
配列の宣言は
int a[10];
のようにしてきましたが、
array<int>^ a=gcnew array<int>(10);
でも宣言できます。
一般にarray<変数型>^ 変数名=gcnew array<変数型>(要素数);
で配列を宣言することが出来ます。
gcnewは新しく定義するという意味です。
array<String^>^ w=gcnew array<String^>(14);でString^型を収納する配列を用意すると、
その配列の添え字順にdataGridView1のセルに順にデータが入っていきます。

        void g(){
           char i;
           for(i=0;i<9;i++){
             x[i]=i%3;
             y[i]=i/3;
           }
        }
では座標を計算しています。1次元のデータを2次元に対応させるためのものです。
x[0]=0,x[1]=1,x[2]=2
x[3]=0,x[4]=1,x{5]=2
x[6]=0,x[7]=1,x{8]=2
y[0]=0,y[1]=0,y[2]=0
y[3]=1,y[4]=1,y{5]=1
y[6]=2,y[7]=2,y{8]=3
と対応します。これを使えば1次元データを2次元に配置することが出来るのです。
尚、色対応でお分かりかと思いますが、ここでのiは、void f(char g)のgに対応します。
gはセル番号=セルのラベルです。

今回のプログラミンで眼目部分は、void f(char g)です。
これが自己再帰型で使われています。
if(s==100)return;を入れた理由は、すべて計算させるには時間がかかりすぎますので、
100個目で止めるためです。

             h=1;
              if(g>0){
               for(j=0;j<g;j++){
                 if(a[y[g]][x[g]]==a[y[j]][x[j]]){
                   h=0;
                   break;
                 }
               }
             }
では、例えば、g=5のときは

1 2 3
4 5 1
* * *


と他が比べられます。同じものがあるときは、
h=0とすることによって強制的に






             if(h==1){
               if(g+1<9){
                 f(g+1);
               }
              else{
                for(j=0;j<3;j++){
                  dataGridView1->Rows->Add();
                    for(k=0;k<3;k++){
                      dataGridView1[k,j+4*s]->Value=a[j][k];                      
                    }
                  }
                  dataGridView1->Rows->Add();
                  s++;
                }
              }
をスルーさせています。そして、ループが進み

1 2 3
4 5 6
* * *





と問題をクリアさせています。




               if(g+1<9){
                 f(g+1);
               }
の部分はg+1までしか進められません。

0 1 2
3 4 5
6 7 8


セル番号は右図をご覧なればお分かりのようにまでしかないからです。



大事な点を繰り返します。
順列のときと同じでセルのラベル(すなわちセル番号)であるとセルに入っている数字(セルの内容)を明確に区別して下さい。


初歩わかりやすい
上図の右側のiはfor(i=0;i<9;i++)のiに対応し、gはvoid f(char g)のgです。

0 1 2
3 4 5
6 7 8



セル番号は8でしかありませんので、
g+1が9のときは、



              else{
                for(j=0;j<3;j++){
                  dataGridView1->Rows->Add();
                    for(k=0;k<3;k++){
                      dataGridView1[k,j+4*s]->Value=a[j][k];                      
                    }
                  }
                  dataGridView1->Rows->Add();
                  s++;
                }
が実行されて、出来た方陣がDataGridViewに表示されます。
VC++


ここで課題です。現在
初心者
と使われない部分が多いので
実行結果が
はじめてのとなるように変更するにはどうしたらよいでしょうか。

今回のプログラミングがご理解できないときは、VC++講義
第16講 関数の再帰的呼び出しによる3次・4次魔方陣の作成☆
 第1話 魔方陣や数独はなぜ関数の再帰的呼び出しに向いているのか
 第2話 ソース例
 第3話 小改良と実験
 第4話 ソース解説その1
 第5話 ソース解説その2
 第6話 ソース解説その3
 第7話 ソース解説その4
を参照して下さい。


第1話へ 第3話へ


025


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



数学研究室に戻る