最終講 卒業研究と卒業試験
第3話 課題2 9次ラテン方陣の作成
前話の課題の解答例
#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;
g();
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);
}
void g(){
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,sa,ss;
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;
}
}
}
void f(char g){
if(s==100)return; 'すべて計算させるとかなり時間がかかるので100個で止めている。
int i,j,k,h,sa,ss;
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{
sa=s%3;
ss=s/3;
for(j=0;j<3;j++){
if(sa==0)dataGridView1->Rows->Add();
for(k=0;k<3;k++){
dataGridView1[k+4*sa,j+4*ss]->Value=a[j][k];
}
}
if(sa==0)dataGridView1->Rows->Add();
s++;
}
}
}
}
};
}
さらに、改良して計算時間が計測できるように変更したいと思います。
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^
e) {
DateTime hj=DateTime::Now;
s=0;
g();
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);
}
hjとowは現在の時間を取得するための変数です。時間を取得するための型がDateTimeであると理解して下さい。
hjで始まりの現在時刻、owで終わりの現在時刻を取得しています。
DateTime::Nowは現在の時間です。
saは時刻差を計算するための変数です。時刻差を計算する変数の型は、TimeSpanなのです。
また、sa.TotalSecondsは時刻差を秒に変換するためのものです。
さて、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;
g();
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 g(){
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;
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){
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(g>0){
for(j=0;j<g;j++){
if(a[y[g]][x[g]]==a[y[j]][x[j]]){
h=0;
break;
}
}
}
が
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;
}
}
}
}
と変わっています。課題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;
}
}
}
}
で行のチェックをしています。
同じものがあるとh = 0 となり、
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++;
}
}
が実行ず、ループが次に進むようになっています。
尚、皆さんfor(i=0;i<9;i++)の9とif(g+1<81)の81に注意して下さい。
行や列に入る数字(セルの内容)は1から9まで(a[y[g]][x[g]]=i+1; +1があるので0から8は1から9までとなる)
であるのに対して、セル番号は0から80までです。
繰り返しますが、セル番号(セルのラベル)とセルの内容(セルに入る1から9までの数字)は明確に区別しないといけません。
明瞭に区別していないと、プログラムは訳のわからないものとなります。
さて、皆さん課題3
課題2に条件
C ブロックの数字が重複してはならない。
を付け加えてください。
に挑戦しましょう。
第2話へ 第4話へ