幻方(附加生成五十阶以内幻方小程序)
有时又称魔方(该称呼现一般指立方体的魔术方块)或纵横图,由一组排放在正方形中的整数组成,其每行、每列以及两条对角线上的数之和均相等。通常幻方由从1到N2的连续整数组成,其中N为正方形的行或列的数目。因此N阶幻方有N行N列,并且所填充的数为从1到N2。
幻方可以使用N阶方阵来表示,方阵的每行、每列以及两条对角线的和都等于常数M2(N),如果填充数为1,2,3.....,N2,那么有
构造法:
根据构造方法的不同,幻方可以分成三类:奇数阶幻方、 4M阶幻方和 4M+2阶幻方,其中 M为自然数, 2阶幻方不存在。幻方构造法主要有:连续摆数法、阶梯法(楼梯法)、奇偶数分开的菱形法、对称法、对角线法、比例放大法、斯特雷奇法、LUX法、拉伊尔法(基方、根方合成法)、镶边法、相乘法、幻方模式等。
奇数阶幻方构造法
Siamese方法(Kraitchik 1942年,pp. 148-149)是构造奇数阶幻方的一种方法,说明如下:
- 把1放置在第一行的中间。
- 顺序将2,3,......数放在右上方格中。
- 当右上方格出界的时候,则由另一边进入。
- 当右上方格中已经填有数,则把数填入正下方的方格中。
- 按照以上步骤直到填写完所有N2个方格。
(由于幻方的对称性,也可以把右上改为右下、左上以及左下等方位)
以下图5阶幻方为例,1填写在(1,3)(第一行第三列)的位置上;2应当填写在其右上方格即(0,4)中,由于(0,4)超出顶边界,所以从最底行进入,即(5,4);3填写在(5,4)的右上方格(4,5)中;4填写在(4,5)的右上方格(3,6)中,
由于(3,6)超出右边界,所以从最左列进入,即(3,1);5填写在(3,1)的右上方格(2,2)中;6应该填写的方格(1,3)已经被1所占据,因此填写在(2,2)的正下方格(3,2)中;按照上面的步骤直到所有数填入。
阶 | 阶 | 阶 |
魔方阵不是唯一的,比如5阶魔方阵还可以是:
阶 |
偶数阶幻方构造法
4M阶幻方构造法
对于4M阶幻方一般都用对调法,制作起来很容易。如4阶幻方的排列法:
按如上图排列好,再将非主副对角线上的各个数关于中心对调,即成下图:
4M+2阶幻方构造法
加边法
以6阶为例子,先排出4阶的幻方,如上图,再将图中每一个数都加上8m+2=10,有下图:
结果如下:
LUX法
在(4M+2)×(4M+2)个方格的适当格点上,先排出2M+1阶的幻方。在前M+1行的格点,全部标上“L”;在第M+1行的中间格点标上“U”,其余格点标上“L”;在第M+2行的中间格点标上“L”,其余格点标上“U”;在余下的M-1行的格点全部标上“X”。将格点上的数乘以4再减4,再按下面的规则加上1至4其中一个数,填入对应的格上:
4 1 1 4 1 4 L U X 2 3 2 3 3 2
例子:
[ 68 65 96 93 4 1 32 29 60 57 ] 17L 24L 1L 8L 15L [ 66 67 94 95 2 3 30 31 58 59 ] [ 92 89 20 17 28 25 56 53 64 61 ] 23L 5L 7L 14L 16L [ 90 91 18 19 26 27 54 55 62 63 ] [ 16 13 24 21 49 52 80 77 88 85 ] 4L 6L 13U 20L 22L [ 14 15 22 23 50 51 78 79 86 87 ] [ 37 40 45 48 76 73 81 84 9 12 ] 10U 12U 19L 21U 3U [ 38 39 46 47 74 75 82 83 10 11 ] [ 41 44 69 72 97 100 5 8 33 36 ] 11X 18X 25X 2X 9X [ 43 42 71 70 99 98 7 6 35 34 ]
附上我写的一个生成50阶以内幻方的程序(其实二十阶以上就已经没什么意义了....):
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 typedef unsigned long long ull; 5 #define INF 0x3f3f3f3f 6 const ll MAXN = 1e2 + 7; 7 const ll MOD = 1e9 + 7; 8 const double pi = acos(-1); 9 int Matrix[50][50]; 10 int t[50][50]; 11 int n; 12 void Move_pos(int &x, int &y, int a[][50], int m) //奇数阶构造移动类二维指针函数 13 { //这里的奇数阶幻方构造方法是向右上填数字 14 int tx = x, ty = y; 15 x--, y++; 16 if (x == 0) 17 x += m; 18 if (y == m + 1) 19 y -= m; 20 if (a[x][y]) 21 x = tx + 1, y = ty; 22 } 23 void pri_Mat() 24 { 25 for (int i = 1; i <= n; i++) 26 { 27 for (int j = 1; j <= n; j++) 28 printf("%-4d ", Matrix[i][j]); 29 printf("\n"); 30 } 31 } 32 void Siamese(int a[][50], int m) 33 { 34 int pos_x = 1, pos_y = m / 2 + 1; //1在幻方中的位置 35 int cnt = 1; //cnt为要填的数,初始为1 36 a[pos_x][pos_y] = cnt++; 37 while (cnt <= m * m) //m阶幻方要填m*m个数 38 { 39 Move_pos(pos_x, pos_y, a, m); 40 a[pos_x][pos_y] = cnt++; 41 } 42 } 43 int main() 44 { 45 memset(Matrix, 0, sizeof(Matrix)); 46 memset(t, 0, sizeof(t)); 47 printf("请输入要形成的幻方阶数:"); 48 scanf("%d", &n); 49 if (n % 2) //奇数阶构造法(Siamese方法) 50 Siamese(Matrix, n); 51 else if (n % 4 == 0) 52 { 53 for (int i = 1; i <= n; i++) 54 for (int j = 1; j <= n; j++) 55 Matrix[i][j] = (i - 1) * n + j; 56 for (int i = 1; i < n / 2; i++) 57 for (int j = i + 1; j <= n - i; j++) 58 swap(Matrix[i][j], Matrix[n + 1 - i][n + 1 - j]); 59 for (int i = 2; i <= n - 1; i++) 60 for (int j = 1; j <= (i <= n / 2 ? i - 1 : n / 2 - i + 3); j++) 61 swap(Matrix[i][j], Matrix[n + 1 - i][n + 1 - j]); 62 } 63 else 64 { 65 //lux构造4M+2幻方 66 int m = n / 2; 67 Siamese(t, m); 68 for (int i = 1; i <= m; i++) 69 for (int j = 1; j <= m; j++) 70 { 71 Matrix[2 * i - 1][2 * j - 1] = 4 * t[i][j]; 72 Matrix[2 * i - 1][2 * j] = 4 * t[i][j] - 3; 73 Matrix[2 * i][2 * j - 1] = 4 * t[i][j] - 2; 74 Matrix[2 * i][2 * j] = 4 * t[i][j] - 1; 75 if ((i>m/2+2)||(i == m / 2 + 2 && j != m / 2 + 1) || ((i == m / 2 + 1) && (j == m / 2 + 1))) 76 swap(Matrix[2 * i - 1][2 * j - 1], Matrix[2 * i - 1][2 * j]); 77 if (i == m) 78 swap(Matrix[2 * i][2 * j - 1], Matrix[2 * i][2 * j]); 79 } 80 } 81 pri_Mat(); 82 return 0; 83 }