魔方矩阵 幻方 九宫图 河洛图

在《射雕》中郭黄二人被裘千仞追到黑龙潭,躲进瑛姑的小屋。瑛姑出了一道题:数字1~9填到三行三列的表格中,要求每行、每列、及两条对角线上的和都相等。这道题难倒了瑛姑十几年,被黄蓉一下子就答出来了。

平面魔方的一般定义:将自然数 1 到 N2 排列 N 行 N 列的方阵,使每行、每列及两条主对角线上的 N 个数的和都等于 N(N2+1)/2,这样的方阵称为 N 阶幻方。

  通过搜索整理后,得到下面的算法:

  对平面魔方的构造,分为三种情况:N为奇数、N为4的倍数、N为其它偶数(4n+2的形式)

(1) N 为奇数时

  (1) 将1放在第一行中间一列;

  (2) 从2开始直到n×n止各数依次按下列规则存放:

  按 45°方向行走,如向右上

  每一个数存放的行比前一个数的行数减1,列数加1

  (3) 如果行列范围超出矩阵范围,则回绕。

  例如1在第1行,则2应放在最下一行,列数同样加1;

  (4) 如果按上面规则确定的位置上已有数,或上一个数是第1行第n列时,

  则把下一个数放在上一个数的下面。

(2)N为4的倍数时

  采用对称元素交换法。

  首先把数1到n×n按从上至下,从左到右顺序填入矩阵

  然后将方阵的所有4×4子方阵中的两对角线上位置的数关于方阵中心作对

  称交换,即a(i,j)与a(n+1-i,n+1-j)交换,所有其它位置上的数不变。

  (或者将对角线不变,其它位置对称交换也可)

(3)N 为其它偶数时

  n为偶数,且不能被4整除 (n=6,10,14,18,22……;n=4k+2,k=1,2,3,4,5……) 

  以n=10为例。这时,k=2 

 (1) 把方阵分为A,B,C,D四个象限,这样每一个象限肯定是奇数阶。 

 用楼梯法,依次在A象限,D象限,B象限,C象限按奇数阶幻方的填法填数。 

6阶幻方第一步: 

   8   1   6 | 26  19  24 

   3   5   7 | 21  23  25 

   4   9   2 | 22  27  20 

------------------------- 

  35  28  33 | 17  10  15 

  30  32  34 | 12  14  16 

  31  36  29 | 13  18  11 

(2) 在A象限的中间行、中间格开始,按自左向右的方向,标出k格。 

A象限的其它行则标出最左边的k格。 

将这些格,和C象限相对位置上的数,互换位置。 

6阶幻方第二步: 

  35*  1   6 | 26  19  24 

   3  32*  7 | 21  23  25 

  31*  9   2 | 22  27  20 

------------------------- 

   8* 28  33 | 17  10  15 

  30   5* 34 | 12  14  16 

   4* 36  29 | 13  18  11 

(3) 在B象限任一行的中间格,自右向左,标出k-1列。 

(注:6阶幻方由于k-1=0,所以不用再作B、D象限的数据交换) 

将B象限标出的这些数,和D象限相对位置上的数进行交换,就形成幻方。 

6阶幻方: 

  35   1   6 | 26  19* 24 

   3  32   7 | 21  23* 25 

  31   9   2 | 22  27* 20 

------------------------- 

   8  28  33 | 17  10* 15 

  30   5  34 | 12  14* 16 

   4  36  29 | 13  18* 11 

最后的单偶阶用指针好难弄,如果会的请指教下,以下是代码:

  1 #include <stdio.h>
2
3 //进行数字交换
4 void Swap(int *x,int *y){
5 int temp;
6 temp=*x;
7 *x=*y;
8 *y=temp;
9 }
10 //当输入数字为奇数时,这个是为了处理单偶阶幻方
11 void OddMatrixCube(int a[][18],int min,int max,int minRow,int minCol,int n){
12 //printf("%x\n",a);
13 int row=minRow,col=minCol+n/2,preRow,preCol;
14 do{
15 if(row<minRow)
16 row=minRow+n-1;
17 if(col<minCol)
18 col=minCol+n-1;
19 if(a[row][col]==0)
20 a[row][col]=min;
21 else{
22 row=preRow+1;
23 col=preCol;
24 a[row][col]=min;
25 }
26 preRow=row;
27 preCol=col;
28 row -=1;
29 col -=1;
30 min++;
31 }while(min<=max);
32 }
33
34 void MatrixCube(int n){
35 //定义一个数组a[n][n]取得连续的内存空间4*n*nbyte
36 //定义一个指针**p来进行地址操作,row*n为行数 ,col为列数,preRow*n为前一行,preCol为前一列
37 int a[n][n],**p,row,col,preRow,preCol,total;
38 p=a;
39 //初始化数组,为了判断右上是否有数字
40 for(row=0;row<n;row++){
41 for(col=0;col<n;col++){
42 *(p+row*n+col)=0;
43 //a[row][col]=n*row+col+1;
44 //printf("%d\n",*(p+row*n+col));
45 //printf("%x\n",p+row*n+col);
46 }
47 }
48 //当N为奇数时
49 if(n%2!=0){
50 //OddMatrixCube(p,1,n*n,0,0,n,0);
51 total=1;
52 row=0;col=n/2;
53 do{
54 if(row<0)
55 row=n*(n-1);
56 if(col<0)
57 col=n-1;
58 if(*(p+row+col)==0)
59 *(p+row+col)=total;
60 else {
61 row=preRow+n;
62 col=preCol;
63 *(p+row+col)=total;
64 }
65 //记住当前行列预防右上的位置已经有数字时候可以放回当前的正下位置
66 preRow=row;
67 preCol=col;
68 row=row-n;
69 col-=1;
70 total++;
71 }while(total<=n*n);
72 }
73 //当N能够被4整除时
74 else if(n%4==0){
75 //将数字从上到下,从左到右填到数组中
76 int k;
77 for(col=0;col<n;col++){
78 for(row=0;row<n;row++){
79 *(p+row*n+col)=n*col+row+1;
80 //a[row][col]=n*row+col+1;
81 //printf("%d\n",*(p+row*n+col));
82 //printf("%x\n",p+row*n+col);
83 }
84 }
85 //正斜反斜对角线数字互换
86 for(k=0;k<n;k++){
87 if(k<n/2)
88 Swap(p+n*k+k,p+n*(n-k-1)+n-k-1);
89 else
90 Swap(p+n*(n-k-1)+k,p+n*k+n-k-1);
91 }
92 }
93 //当N为4*n+2时
94 else{
95 int child;
96 for(child=0;child<4;child++){
97 if(child==0)
98 OddMatrixCube(a,child*n*n/4+1,(child+1)*n*n/4,0,0,n/2);
99 else if(child==1)
100 OddMatrixCube(a,child*n*n/4+1,(child+1)*n*n/4,n/2,n/2,n/2);
101 else if(child==2)
102 OddMatrixCube(a,child*n*n/4+1,(child+1)*n*n/4,0,n/2,n/2);
103 else
104 OddMatrixCube(a,child*n*n/4+1,(child+1)*n*n/4,n/2,0,n/2);
105 }
106 int m=(n-2)/4,temp,k;
107 for(row=0;row<n/2;row++)
108 {
109 // 步骤二
110 for(col=0;col<m;col++)
111 {
112 k=(row==n/4)?n/4+col:col;
113 temp=a[row][k];
114 a[row][k]=a[row+n/2][k];
115 a[row+n/2][k]=temp;
116 }
117 // 步骤三
118 for(col=0;col<m-1;col++)
119 {
120 k=n/2+n/4+col;
121 temp=a[row][k];
122 a[row][k]=a[row+n/2][k];
123 a[row+n/2][k]=temp;
124 }
125 }
126 }
127 for(row=0;row<n;row++){
128 for(col=0;col<n;col++)
129 printf("%-3d ",*(p+row*n+col));
130 printf("\n");
131 }
132 }
133
134
135 int main(int argc,int *argv[]){
136 int n;
137 loop:
138 printf("请输入魔方矩阵的方数N:");
139 scanf("%d",&n);
140 MatrixCube(n);
141 printf("魔方矩阵的行||列||对角线只和SUM:%d\n",n*(n*n+1)/2);
142 if(n==0)
143 exit(0);
144 else
145 goto loop;
146 system("PAUSE");
147 return 0;
148 }

  

  

posted @ 2011-08-06 13:02  Hanoi  阅读(2282)  评论(1编辑  收藏  举报