第18講 対角線法による魔方陣自動生成速度の1万倍加へ

第7話 対角線法の完成

実行画面
03 14 02 15

10 13 08 03
16 04 09 05
01 15 06 12
07 02 11 14

10 13 08 03
05 04 09 16
12 15 06 01
07 02 11 14

生成された4次魔方陣=10
魔方陣生成にかかった4時間は0.036000秒です。

を実現するプログラム例
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
void f(int g); //魔方陣を作り出す社員
void hy(); //出来た順列をコンソールに表示させる社員
void zy(); //座標作成社員
void hy1(int a[10][10]); //番号付けが上手くいっているかを確認する社員
void g(); //座標作りが正しく出来ているかを確認する確認する社員
int cn,n;
int m[10][10]; //少し大きめに配列要素数を取っておく
int y[100],x[100];
int main(){
  clock_t hj,ow;
  srand(1);
  printf("n=");
  fflush(0); //pirntfを先に実行させるためのお呪い
  scanf("%d",&n);
  cn=0;
  hj=clock();
  zy();
  f(0);
  ow=clock();
  printf("生成された%d次魔方陣=%d\n",n,cn);
  printf("魔方陣生成にかかった時間は%f秒です。\n",(double)(ow - hj) / CLOCKS_PER_SEC);
}
void zy(){ //座標作成社員
  int a[10][10];
  int i,j,cn;
  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=0j;j<n;j++){
      if(a[i][j]==-1){
        a[i][j]=cn;
        cn++;
      }
    }
  }
  for(i=0;i<n;i++){
    for(j=0j;j<n;j++){
      y[a[i][j]]=i;
      x[a[i][j]]=j;
    }
  }
  //g();
}
void hy1(int a[10][10]){
  int i,j;
  for(i=0;i<n;i++){
    for(j=0j;j<n;j++){
      if(a[i][j]<10)printf("0%d ",a[i][j]);
      if(a[i][j]>=10)printf("%d ",a[i][j]);
    }
    printf("\n");
  }
  printf("\n");
}
void g(){
  int i,a[10][10];
  for(i=0;i<n*n;i++){
    a[y[i]][x[i]]=i;
  }
  hy1(a);
}
void f(int g){
  int i,j,h,w,ih;
  ih=rand()%(n*n);
  for(i=0;i<n*n;i++){
    m[y[g]][x[g]]=((ih+i)%(n*n))+1;
    h=1;
    if(g>0){
      for(j=0;j<g;j++){
        if(m[y[g]][x[g]]==m[y[j]][x[j]]){
          h=0;
          break;
        }
      }
    }
    if(h==1){
      if(y[g]==n-1 && x[g]==n-1){
        w=0;
        for(j=0;j<n;j++)w=w+m[y[j]][j];
        if(w!=(n*(n*n+1))/2)h=0;
      }
    }
    if(h==1){
      if(y[g]==n-1 && x[g]==0){
        w=0;
        for(j=0;j<n;j++)w=w+m[j][n-1-j];
        if(w!=(n*(n*n+1))/2)h=0;
      }
    }
    if(h==1){
      if(y[g]==0 && x[g]==n-2){
        w=0;
        for(j=0;j<n;j++)w=w+m[y[g]][j];
        if(w!=(n*(n*n+1))/2)h=0;
      }
    }
    if(h==1){
      if(g>2*n && y[g]>0 && x[g]==n-1){
        w=0;
        for(j=0;j<n;j++)w=w+m[y[g]][j];
        if(w!=(n*(n*n+1))/2)h=0;
      }
    }
    if(h==1){
      if(y[g]==n-2 && x[g]==0){
        w=0;
        for(j=0;j<n;j++)w=w+m[j][x[g]];
        if(w!=(n*(n*n+1))/2)h=0;
      }
    }
    if(h==1){
      if(g>2*n && y[g]==n-1 && x[g]>0){
        w=0;
        for(j=0;j<n;j++)w=w+m[j][x[g]];
        if(w!=(n*(n*n+1))/2)h=0;
      }
    }
    if(h==1){
      if(g+1<n*n){
        f(g+1);
        if(cn==10)return;
      }
      else{
        cn++;
        hy();
        if(cn==10)return;
      }
    }
  }
}
void hy(){
  int i,j;
  for(i=0;i<n;i++){
    for(j=0;j<n;j++){
      if(n>3){
        if(m[i][j]<10)printf("0%d ",m[i][j]);
        if(m[i][j]>=10)printf("%d ",m[i][j]);
      }
      if(n==3)printf("%d ",m[i][j]);
    }
    printf("\n");
  }
  printf("\n");
}
魔方陣自動生成アプリVer.2(対角線法)


第10講版ならば、10時間待っても出てこなかった5次魔方陣が

11 16 10 23 05
09 20 21 01 14
04 08 12 22 19

17 03 08 12 25
21 18 15 06 05
16 13 10 24 02
07 20 23 01 14
04 11 09 22 19

生成された5次魔方陣=10
魔方陣生成にかかった時間は200.246000秒です。
と3,4分出てきました。
実験は途中で打ち切ってしまったので、
第10講版ならどれだけかかるか分かりませんが、
仮に10時間だとすれば、
10×3600÷
200=1800倍です。
おそらくはそれよりずっと上でしょう。

それでn=6としたら・・・・
待てども待てども出てこない!!!

対角線法では無理なのでしょうか。
いえいえ、そんなことありません。
私の実験では、7次ぐらいまで可能です。
どうすればいい?
前話の
後の実験コード生成のために、
srand(1);

srand((unsigned) time(NULL));
とはせずにそのままにしておきましょう。
後にどのシード値(乱数系列の種)が適しているかを調べますので、
srand(i);
などとして、
for文でiの値を1から1000ぐらいまで変化させて、
最適シード値(乱数系列の種)を探します。

がヒントです。




第6話へ 第8話へ

a


初心者のための excel 2016 マクロ VBA 入門講義 基礎から応用まで
vc++ c言語 c++ 入門 初心者 基礎から応用まで
eclipse c++ 入門
魔方陣 数独で学ぶ VBA 入門

数独のシンプルな解き方・簡単な解法の研究
VB講義へ
VB講義基礎へ
初心者のための世界で一番わかりやすいVisual C++入門基礎講座
初心者のための世界で一番わかりやすいVisual Basic入門基礎講座

初心者のための世界で一番わかりやすいVBA入門講義(基礎から応用まで)
初心者のための VC++による C言語 C++ 入門 基礎から応用まで第1部
eclipse java 入門
java 入門 サイト 基礎から応用まで
本サイトトップへ