第17講 関数の再帰的呼び出しによる3次・4次魔方陣ソフトの改良
第7話 奇数版枠番号付けの解説その2
            else if(i<2*n+(n*n-3*n)/2){
              x[i]=(i-2*n+1)%(n-2);
              y[i]=(i-2*n+1)/(n-2);
              if(x[i]>=y[i])x[i]++;
              if(x[i]>=n-y[i]-1)x[i]++;
            }
            else if(
i<3*n-1+(n*n-3*n)/2){
              x[i]=i-2*n-(n*n-3*n)/2;
              y[i]=m;
              if(x[i]>=y[i])x[i]++;
            }
            else{
              x[i]=(i-2*n)%(n-2);
              y[i]=(i-2*n)/(n-2);
              if(x[i]>=n-y[i]-1)x[i]++;
              if(x[i]>=y[i])x[i]++;
            }

まず、i<2*n+(n*n-3*n)/2から解説しましょう。

4
10 11
12 13 14
15 16 17 18
19 20 21
4 22 23 24


nに5を代入すると、2×5+(5×5−3×5)÷2=15

15

になることが分かります。
ですから、iの対象範囲は9から14までとなります。
なぜうまく15となるのでしょうか。

実は次の計算をしています。
2×n−1+{n×n−(2×n−1)−(n−1)}÷2
=2×n−1+(n×n−3×n+2)÷2
=2×n−1+(n×n−3×n)÷2+1
=2×n+(n×n−3×n)÷2
対角線と逆対角線でセル数が2×n−1個ですから、


は2×n−1番目です。
番号は0から始まるからです。

では、{n×n−(2×n−1)−(n−1)}÷2においては何を計算しているのでしょうか。

対角線と逆対角線のセルと
中央行の中央のセル以外のセルを除いたセルすなわち

15 16 17 18



を除いたセルとの
の合計数を全セル数から引いています。


−(2×n−1)で対角線と逆対角線の合計セル数を引いて、
−(n−1)で

15 16 17 18

中央行の中央のセルを除いた
セル数分を引いています。



10 11
12 13 14


そして、それを2で割れば左表の水色以外のセル(9,10,11,13,13,14)数
になるのはお分かりでしょうか。





では、
            else if(i<3*n-1+(n*n-3*n)/2){
              x[i]=i-2*n-(n*n-3*n)/2;
              y[i]=m;
              if(x[i]>=y[i])x[i]++;
            }

i<3*n-1+(n*n-3*n)/2は何でしょうか。
実はこれは
 2×n−1+{n×n−(2×n−1)−(n−1)}÷2+(n−1)
=2×n−1+(n×n−3×n+2)÷2+n−1
=2×n−1+(n×n−3×n)÷2+1+n−1
=3×n−1+(n×n−3×n)÷2
=3*n−1+(n*n−3*n)/2
つまり前回の2*n+(n*n-3*n)/2(n-1)を加えているのです。
(n-1)

15 16 17 18



を除いたセル数です。


ですから3*n-1+(n*n-3*n)/2

19

を指すことになりましてi<3*n-1+(n*n-3*n)/2の指し示す範囲は、
15,16,17,18とうまくいきます。



              x[i]=i-2*n-(n*n-3*n)/2;
              y[i]=m;
              if(x[i]>=y[i])x[i]++;

については、y[i]=m;のmはn/2でしたからm=でうまくいっています。
i-2*n-(n*n-3*n)/2はiから2*n+(n*n-3*n)/2を引いていますので、
0,1,2,3と動いていき、if(x[i]>=y[i])x[i]++;によって、
0,1,3,4となります。




最後の
            else{
              x[i]=(i-2*n)%(n-2);
              y[i]=(i-2*n)/(n-2);
              if(x[i]>=n-y[i]-1)x[i]++;
              if(x[i]>=y[i])x[i]++;
            }

の対象は残りの

19 20 21
22 23 24

19,20,21,22,23,24
であることはお分かりでしょう。








尚、n=5の場合で説明しましたが、奇数ならいくつでも成り立つ普遍的(汎用性の広い)プログラムです。
是非、皆さんn=7やn=9などでトレースして普遍性(一般性)を確認されて下さい。



第17講第6話 第17講第8話へ

VC++講義第1部へ
vb講義へ
VB講義基礎へ
初心者のための世界で一番わかりやすいVisual C++入門基礎講座
初心者のための世界で一番わかりやすいVisual Basic入門基礎講座