最終講 卒業研究と卒業試験
第4話 課題3 9次ラテン方陣にブロックの条件を加える
解答例
#pragma once
int a[9][9];
int x[81],y[81];
int s;
namespace 順列方陣 {
using namespace System;
・
・
・
#pragma endregion
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^
e) {
DateTime hj=DateTime::Now;
s=0;
h();
f(0);
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);
DateTime ow=DateTime::Now;
TimeSpan sa=ow-hj;
w[8]=L"時";w[9]=L"間";w[10]=L"計";w[11]=L"則";w[12]=L":";w[13]=(sa.TotalSeconds).ToString();
dataGridView1->Rows->Add(w);
}
void h(){
char i;
for(i=0;i<81;i++){
x[i]=i%9;
y[i]=i/9;
}
}
void f(char g){
if(s==100)return; 'すべて計算させるとかなり時間がかかるので100個で止めている。
int i,j,k,h,xs,ys;
for(i=0;i<9;i++){
a[y[g]][x[g]]=i+1;
h=1;
if(y[g]>0){
for(j=0;j<y[g];j++){
if(a[y[g]][x[g]]==a[j][x[g]]){
h=0;
break;
}
}
}
if(h==1){
if(x[g]>0){
for(j=0;j<x[g];j++){
if(a[y[g]][x[g]]==a[y[g]][j]){
h=0;
break;
}
}
}
}
if(h==1){
xs=x[g]/3;
ys=y[g]/3;
for(j=0;j<=y[g]-3*ys;j++){
for(k=0;k<3;k++){
if(j==y[g])if(k==x[g])break;
if((y[g]!=3*ys+j) && (x[g]!=3*xs+k)){
if(a[y[g]][x[g]]==a[3*ys+j][3*xs+k]){
h=0;
break;
}
}
}
if(h==0)break;
}
}
if(h==1){
if(g+1<81){
f(g+1);
}
else{
for(j=0;j<9;j++){
dataGridView1->Rows->Add();
for(k=0;k<9;k++){
dataGridView1[k,j+10*s]->Value=a[j][k];
}
}
dataGridView1->Rows->Add();
s++;
}
}
}
}
};
}
実行例
解説
if(h==1){
xs=x[g]/3;
ys=y[g]/3;
for(j=0;j<=y[g]-3*ys;j++){
for(k=0;k<3;k++){
if(j==y[g])if(k==x[g])break;
if((y[g]!=3*ys+j) && (x[g]!=3*xs+k)){
if(a[y[g]][x[g]]==a[3*ys+j][3*xs+k]){
h=0;
break;
}
}
}
if(h==0)break;
}
}
が加えた部分です。
xs=x[g]/3;
ys=y[g]/3;
では何をしているんでしょうか。実はブロック番号を計算しています。
1 | 2 | 3 | |||||||
0 | 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 | |
1 | 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 | |
2 | 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 |
例えば、セル番号49は、ブロック番号(0,2)に対応します。
セル番号の49とき、
for(j=0;j<=y[g]-3*ys;j++){
for(k=0;k<3;k++){
if(j==y[g])if(k==x[g])break;
if((y[g]!=3*ys+j) && (x[g]!=3*xs+k)){
if(a[y[g]][x[g]]==a[3*ys+j][3*xs+k]){
h=0;
break;
}
}
}
if(h==0)break;
}
では、セル番号49とセル番号30,32,39,41の内容が比較されます。
セル番号31,40,48は
for(i=0;i<9;i++){
a[y[g]][x[g]]=i+1;
h=1;
if(y[g]>0){
for(j=0;j<y[g];j++){
if(a[y[g]][x[g]]==a[j][x[g]]){
h=0;
break;
}
}
}
if(h==1){
if(x[g]>0){
for(j=0;j<x[g];j++){
if(a[y[g]][x[g]]==a[y[g]][j]){
h=0;
break;
}
}
}
}
において重複チェックが済んでいまし、セル番号0から順に入れてきてセル番号49までしか数字が入っていませんから、
セル番号50にはまだ数字が入っていないので比較の必要がないわけです。
30 | 31 | 32 |
39 | 40 | 41 |
48 | 49 | 50 |
if(j==y[g])if(k==x[g])break;はセル番号50を検査対象から外すためにあります。
セル番号49に達したら検査を終了するようになっています。
(y[g]!=3*ys+j) && (x[g]!=3*xs+k))は、同行と同列を検査対象から外すためにあります。
31,40,48は一度検査されているのでテストの必要はないわけです。
では、for(j=0;j<=y[g]-3*ys;j++)のj=0;j<=y[g]-3*ys;j++の意味は何でしょうか。
例えば、セル番号39なら
30 | 31 | 32 |
39 | 40 | 41 |
48 | 49 | 50 |
最後の行は検査する必要はありません。
セル番号39までしか数字が入っていないからです。
では皆さん、
課題4
課題3で完成させたソフトに
ブロックの区切り*入れましょう。
課題5
課題4にさらにランダムを入れて自然な数独にしましょう。
に挑戦して、卒業研究課題は終了です。
後は、卒業試験を残すのみとなります。
第3話へ 第5話へ