第16講 関数の再帰的呼び出しによる魔方陣の作成
第1話 順列作成プログラムから魔方陣作成プログラムに変更するには?
順列作成プログラム
#include<iostream>
using namespace std;
void f1(int g);
void f2();
int n,cn;
int a[20];
int main(){
   cout<<"何次順列を作成させるのかキーボードから入力してください。"<<endl;
   cout<<"次数=";
   scanf("%d",&n);
   cn=0;
   f1(0);
   cout<<"順列が"<<cn<<"個できました。"<<endl;
}
void f1(int g){
   int i,j,h;
   for(i=1;i<n+1;i++){
     a[g]=i;
     h=1;
     if(g>0){
       for(j=0;j<g;j++){
         if(a[g]==a[j]){
           h=0;
           break;
         }
       }
     }
     if(h==1){
       if(g+1<n){
         f1(g+1);
       }
       else{
         cn++;
         f2();
       }
     }
   }
}
void f2(){
   int i;
   for(i=0;i<n;i++){
     cout<<a[i]<<" ";
   }
   cout<<endl;
}

皆さん、このプログラムを普遍版魔方陣自動生成プログラムに変更するには何をしなければならないでしょうか。
2つ課題があります。
1つは、1次元に並んでいる順列を2次元に並び尚なさなければならないということです。

1 2 3 4 5 6 7 8 9


1 2 3
4 5 6
7 8 9

2つめの課題は、行・列・対角線の合計がすべてn×(n×n+1)÷2にしなければならないということです。
n×(n×n+1)÷2というのは、n次魔方陣の各数字の和は、
1+2+3+・・・+(n×n-1)+n×n=n×n×(n×n+1)÷2(等差数列の和の公式)ですから、一辺の和はそれをnで割った
n×n×(n×n+1)÷2÷n=n×(n×n+1)÷2
であるからです。

一つめの課題を成就するためには、グローバル配列
int a[10][10];  
(理論的には何次でも可能ですが、現実的には現時点では4次が限界です。
ただ、改良を重ねていくと10次ぐらいまでは可能となりますのでとりあえず10としてあります。
もちろん、さらに学習が進むと30次ぐらいまでが可能になってきます。)
を用意して、
関数f1には、
int x,y;
を宣言しておいて、
x=g%n;
y=g/n;
としてa[y][x]にfor文で代入していけばよいのです。

行・列・対角線合計については、

1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16

ピンクのセルに到達したとき、行や列や対角線の合計を確認すればよいのです。
例えば、次ようなif文を用意すればよいでしょう。
if(x==n-1){
  w=0;
  for(j=0;j<n;j++){
    w+=a[y][j];
  }
  if(w!=n*(n*n+1)/2)h=0;
}
では皆さん、普遍版魔方陣自動生成プログラムに挑戦しましょう。


第15講第11話へ 第2話へ

戻る

C言語 C++講義第1部へ
VB講義へ
VB講義基礎へ

vc++講義へ第1部へ
初心者のための世界で一番わかりやすいVisual C++入門基礎講座
初心者のための世界で一番わかりやすいVisual Basic入門基礎講座
初心者のための世界で一番わかりやすいVBA入門講義(基礎から応用まで)