第27講 数独(ナンプレ)自動生成
第9話 新しい番号付けとそれに対応する座標を設定するプログラムの解説その1

プログラム主要部分再掲
    ・・・
void zh(int n,int *p,int *q){
   int i,j,k,l,cn,a[9][9];
   for(i=0;i<3;i++){
     for(j=0;j<3;j++){
        for(k=0;k<3;k++){
          for(l=0;l<3;l++){
             a[3*i+k][3*j+l]=9*(3*i+j)+3*k+l;
          }
        }
     }
   }
   for(i=0;i<n;i++){
     for(j=0;j<n;j++){
        p[a[i][j]]=j;
        q[a[i][j]]=i;
     }
   }
}
    ・・・・
void h(int m[10][10],int n){
   int i,j;
   for(i=0;i<n+1;i++){
     if(i%3==0){
        for(j=0;j<n+4;j++){
          if(j<n+3 && j%4!=0)cout<<" **";
          if(j%4==0)cout<<" *";
        }
        cout<<endl;
        if(i==n)break;
     }
     for(j=0;j<n+1;j++){
        //if(m[i][j]<10)cout<<"0"<<m[i][j]<<" ";
        if(j==0)cout<<" * ";
        if(j>0 && j%3==0)cout<<"* ";
        if(j<n){
          if(m[i][j]<10)cout<<"0"<<m[i][j]<<" ";
          if(m[i][j]>=10)cout<<m[i][j]<<" ";
        }
     }
     cout<<endl;
   }
}

解説
解説しなければならないことは2つです。
void zh(int n,int *p,int *q)とvoid h(int m[10][10],int n)についてです。
まず、void zh(int n,int *p,int *q)から説明しましょう。
   int i,j,k,l,cn,a[9][9];
において、2次元配列a[9][9]を用意する意味は、
優秀な皆さんならお分かりですね。
座標を設定する前に、
新しい番号付け
i
をするためですね。
void zh(int n,int *p,int *q)の任務は、
座標を設定することですが、
設定する前には数字を入れる順番gを先に、
決めておかないと出来ません。
元々は
void zh(int n,int *p,int *q){
   int i,j,cn;
   int a[10][10];
   for(i=0;i<n;i++)
     for(j=0;j<n;j++)
        a[i][j]=-1;
   for(i=0;i<n;i++)a[i][i]=i;
   cn=n;
   for(i=0;i<n;i++){
     if(a[i][n-1-i]==-1){
        a[i][n-1-i]=cn;
        cn++;
     }
   }
   for(i=0;i<n;i++){
     for(j=0;j<n;j++){
         if(a[i][j]==-1){
           a[i][j]=cn;
           cn++;
         }
     }
   }
   for(i=0;i<n;i++){
     for(j=0;j<n;j++){
        p[a[i][j]]=j;
        q[a[i][j]]=i;
     }
   }
}
となっていたことを思い出せば、
a[9][9]を用意する意味は明らかです。
問題は、
   for(i=0;i<3;i++){
     for(j=0;j<3;j++){
        for(k=0;k<3;k++){
          for(l=0;l<3;l++){
             a[3*i+k][3*j+l]=9*(3*i+j)+3*k+l;
          }
        }
     }
   }
4次元for文です。
2次元for文でさえ、頭が混乱するのに4次元です。
ヒントに、
   for(i=0;i<3;i++){
     for(j=0;j<3;j++){
        for(k=0;k<3;k++){
          for(l=0;l<3;l++){
             a[3*i+k][3*j+l]=9*(3*i+k)+3*j+l;
          }
        }
     }
   }
としたのでは、
   for(i=0;i<3;i++){
     for(j=0;j<3;j++){
        a[i][j]=9*i+j;
     }
   }
と書いたことを思い出して下さい。
この番号付けでは、

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

となってしまいますね。
どうして、
   for(i=0;i<3;i++){
     for(j=0;j<3;j++){
        for(k=0;k<3;k++){
          for(l=0;l<3;l++){
             a[3*i+k][3*j+l]=9*(3*i+k)+3*j+l;
          }
        }
     }
   }

   for(i=0;i<3;i++){
     for(j=0;j<3;j++){
        a[i][j]=9*i+j;
     }
   }
は同じなのでしょうか。
これが分かれば、
   for(i=0;i<3;i++){
     for(j=0;j<3;j++){
        for(k=0;k<3;k++){
          for(l=0;l<3;l++){
             a[3*i+k][3*j+l]=9*(3*i+j)+3*k+l;
          }
        }
     }
   }
によって、

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

が実現できることを理解できます。
それぞれの場合の動きを次話でトレースしてみましょう。


第8話へ 第10話へ


a

eclipse c++ 入門講義第1部へ

eclipse c++ 入門講義第2部へ


魔方陣 数独で学ぶ VBA 入門
数独のシンプルな解き方・簡単な解法の研究
VB講義へ
VB講義基礎へ
初心者のための世界で一番わかりやすいVisual C++入門基礎講座
初心者のための世界で一番わかりやすいVisual Basic入門基礎講座
初心者のための世界で一番わかりやすいVBA入門講義(基礎から応用まで)
初心者のための VC++による C言語 C++ 入門 基礎から応用まで第1部
eclipse java 入門
java 入門 サイト 基礎から応用まで
VC++ C言語 C++ 入門 初心者 基礎から応用まで
本サイトトップへ