当前位置:   article > 正文

【C语言】魔方阵的实现(最全)_魔方阵c语言程序设计

魔方阵c语言程序设计

 魔方阵的实现(最全)

一、什么是魔方阵

魔方矩阵,又称幻方,是具有相同的行数和列数,并在每行每列、对角线上的和都相等的矩阵。

N阶幻方,即将自然数1到N^{2}排成N行N列的方阵,使每行、每列及两条主对角线上的 N 个数的和相等,等于 M=\frac{n\left ( n^{2}+1 \right )}{2}

二、魔方阵的分类

对于魔方阵的构造,可分为一下三种类型:

  • 奇数阶(N为奇数 [2n+1的形式] )
  • 单偶数阶(N为4的倍数 [4n的形式] )
  • 双偶数阶(N为其他偶数 [4n+2的形式] )

三、魔方阵及代码实现

1、奇数阶魔方阵(n为奇数)

一般解法:

  1. 将1放在第一行中间一列
  2. 从2开始到n^{2}为止,每个数字的排放规律为:每一个数字排放的行比前一个数字的行数减1,每个数字排放的列比前一个数字的列数加1
  3. 行的特殊情况:如果前一个数字的行数为1,那么该数字排在第n行
  4. 列的特殊情况:如果前一个数字的列数为n,那么该数字排在第1列
  5. 其他情况:如果按照上面规律确定的位置上已经有数字,则把要排的数字放在上一个数字的下面。

下面为5阶魔方阵例子(各位读者可以根据以上解法思考):

17241815
23571416
46132022
101219213
11182529

代码实现: 

  1. //奇数阶魔方阵
  2. void odd_number(int n)
  3. {
  4. int i;
  5. int row,line,row_0,line_0;//row为列坐标,line为行坐标,row_0记录行坐标,line_0记录列坐标
  6. line=0;row=(n+1)/2-1;//初始化行、列坐标
  7. a[line][row]=1;
  8. for(i=2;i<=n*n;i++)
  9. {
  10. line_0=line;row_0=row;//记录上一次循环行、列坐标
  11. if(line==0&&row==n-1)//第1行第n列的情况
  12. {
  13. line=n-1;//行坐标转到第n行
  14. row=0;//列坐标转到第1行
  15. }
  16. else if(line==0)//第1行非第n列的情况
  17. {
  18. line=n-1;//行坐标转到第n行
  19. row++;//列坐标+1
  20. }
  21. else if(row==n-1)//第n列非第1行的情况
  22. {
  23. row=0;//列坐标转到第1列
  24. line--;//行坐标-1
  25. }
  26. else//普通情况
  27. {
  28. line--;//行坐标-1
  29. row++;//列坐标+1
  30. }
  31. if(a[line][row]!=0)//判断该位置是否有数字
  32. {
  33. line=line_0+1;//(基于本次for循环开始的坐标)行坐标-1,转跳到下一行
  34. row=row_0;//(基于本次for循环开始的坐标)列坐标不变
  35. }
  36. a[line][row]=i;//赋值
  37. }
  38. }

2、单偶数阶魔方阵(n为偶数,且不能被4整除)

一般解法(以10阶魔方阵为例):

  1. 首先把魔方阵均分为四个象限(形成四个奇数阶魔方阵),用奇数阶魔方阵填充的方法依次填充四个象限(顺序为ADBC)。
    AB
    CD
    172418156774515865
    235714167355576466
    461320225456637072
    1012192136062697153
    111825296168755259
    92997683904249263340
    98808289914830323941
    79818895972931384547
    85879496783537444628
    869310077843643502734
  2. 对于A象限的中间行,从中间格开始,自左至右标出k格;对于A象限的其他行,标出最左边k格(其中,k满足表达式n=4k+2)。
    172418156774515865
    235714167355576466
    461320225456637072
    1012192136062697153
    111825296168755259
    92997683904249263340
    98808289914830323941
    79818895972931384547
    85879496783537444628
    869310077843643502734
  3. 将A象限标出的数字与C象限中对应位置上的数互换位置。
    929918156774515865
    9880714167355576466
    468895225456637072
    8587192136062697153
    869325296168755259
    17247683904249263340
    2358289914830323941
    79811320972931384547
    10129496783537444628
    111810077843643502734
  4. 对于B象限的所有行的中格,自左向右标出k-1格,并将其与D象限中对应位置的数字交换。
    929918156774515865
    9880714167355576466
    468895225456637072
    8587192136062697153
    869325296168755259
    17247683904249263340
    2358289914830323941
    79811320972931384547
    10129496783537444628
    111810077843643502734
    929918156774265865
    9880714167355326466
    468895225456387072
    8587192136062447153
    869325296168505259
    17247683904249513340
    2358289914830573941
    79811320972931634547
    10129496783537694628
    111810077843643752734

 代码实现:

  1. void single_even_number(int n)
  2. {
  3. int i,j;
  4. int k,line,row,line_0,row_0;//k是与n相关的参数,line为行坐标,row为列坐标,line_0记录行坐标,row_0记录列坐标
  5. k=(n-2)/4;
  6. //A象限
  7. line=0;row=k;//初始化A象限行列坐标
  8. a[line][row]=1;
  9. for(i=2;i<=(2*k+1)*(2*k+1);i++)//A象限的数字范围为1~(2*k+1)*(2*k+1)
  10. {
  11. line_0=line;row_0=row;//记录该次循环的初始行列坐标
  12. if(line==0&&row==2*k)//第0行第2*k列的情况
  13. {
  14. line=2*k;//行坐标转为2*k
  15. row=0;//列坐标转为0
  16. }
  17. else if(line==0)//第0行非第2*k列的情况
  18. {
  19. line=2*k;//行坐标转为2*k
  20. row++;//列坐标+1
  21. }
  22. else if(row==2*k)//第2*k列非第0行的情况
  23. {
  24. row=0;//列坐标转为0
  25. line--;//行坐标-1
  26. }
  27. else//普通情况
  28. {
  29. line--;//行坐标-1
  30. row++;//列坐标+1
  31. }
  32. if(a[line][row]!=0)//判断是否遇到该位置有数字的情况
  33. {
  34. line=line_0+1;
  35. row=row_0;
  36. }
  37. a[line][row]=i;//赋值
  38. }
  39. //D象限
  40. line=2*k+1;row=3*k+1;//初始化D象限行列坐标
  41. a[2*k+1][3*k+1]=(2*k+1)*(2*k+1)+1;
  42. for(i=(2*k+1)*(2*k+1)+2;i<=2*(2*k+1)*(2*k+1);i++)//D象限数字范围(2*k+1)*(2*k+1)+1~2*(2*k+1)*(2*k+1)
  43. {
  44. line_0=line;row_0=row;//记录该次循环的初始行列坐标
  45. if((line==2*k+1)&&(row==4*k+1))//第(2*k+1)行第(4*k+1)列的情况
  46. {
  47. line=4*k+1;//行坐标转为4*k+1
  48. row=2*k+1;//列坐标转为2*k+1
  49. }
  50. else if(line==2*k+1)//第(2*k+1)行非第(4*k+1)列的情况
  51. {
  52. line=4*k+1;//行坐标转为4*k+1
  53. row++;//列坐标+1
  54. }
  55. else if(row==4*k+1)//第(4*k+1)列非第(2*k+1)行的情况
  56. {
  57. row=2*k+1;//列坐标转为2*k+1
  58. line--;//行坐标-1
  59. }
  60. else//普通情况
  61. {
  62. line--;//行坐标-1
  63. row++;//列坐标+1
  64. }
  65. if(a[line][row]!=0)//判断是否遇到该位置有数字的情况
  66. {
  67. line=line_0+1;
  68. row=row_0;
  69. }
  70. a[line][row]=i;//赋值
  71. }
  72. //B象限
  73. line=0;row=3*k+1;//初始化B象限行列坐标
  74. a[line][row]=2*(2*k+1)*(2*k+1)+1;
  75. for(i=2*(2*k+1)*(2*k+1)+2;i<=3*(2*k+1)*(2*k+1);i++)//B象限数字范围2*(2*k+1)*(2*k+1)+1~3*(2*k+1)*(2*k+1)
  76. {
  77. line_0=line;row_0=row;//记录该次循环的初始行列坐标
  78. if((line==0)&&(row==4*k+1))//第0行第(4*k+1)列的情况
  79. {
  80. line=2*k;//行坐标转为2*k
  81. row=2*k+1;//列坐标转为2*k+1
  82. }
  83. else if(line==0)//第0行非第(4*k+1)列的情况
  84. {
  85. line=2*k;//行坐标转为2*k
  86. row++;//列坐标+1
  87. }
  88. else if(row==4*k+1)//第(4*k+1)列非第0行的情况
  89. {
  90. row=2*k+1;//列坐标转为2*k+1
  91. line--;//行坐标-1
  92. }
  93. else//普通情况
  94. {
  95. line--;//行坐标-1
  96. row++;//列坐标+1
  97. }
  98. if(a[line][row]!=0)//判断是否遇到该位置有数字的情况
  99. {
  100. line=line_0+1;
  101. row=row_0;
  102. }
  103. a[line][row]=i;//赋值
  104. }
  105. //C象限
  106. line=2*k+1;row=k;//初始化C象限行列坐标
  107. a[line][row]=3*(2*k+1)*(2*k+1)+1;
  108. for(i=3*(2*k+1)*(2*k+1)+2;i<=4*(2*k+1)*(2*k+1);i++)//C象限数字范围3*(2*k+1)*(2*k+1)+1~4*(2*k+1)*(2*k+1)
  109. {
  110. line_0=line;row_0=row;//记录该次循环的初始行列坐标
  111. if((line==2*k+1)&&(row==2*k))//第(2*k+1)行第2*k列的情况
  112. {
  113. line=4*k+1;//行坐标转为4*k+1
  114. row=0;//列坐标转为0
  115. }
  116. else if(line==2*k+1)//第(2*k+1)行非第2*k列的情况
  117. {
  118. line=4*k+1;//行坐标转为4*k+1
  119. row++;//列坐标+1
  120. }
  121. else if(row==2*k)//第2*k列非第(2*k+1)行的情况
  122. {
  123. row=0;//列坐标转为0
  124. line--;//行坐标-1
  125. }
  126. else//普通情况
  127. {
  128. line--;//行坐标-1
  129. row++;//列坐标+1
  130. }
  131. if(a[line][row]!=0)//判断是否遇到该位置有数字的情况
  132. {
  133. line=line_0+1;
  134. row=row_0;
  135. }
  136. a[line][row]=i;//赋值
  137. }
  138. //换A、C象限相关数字的位置
  139. for(i=0;i<2*k+1;i++)//对于A、C象限
  140. {
  141. int j_0,f=0;//j_0记录循环次数,f=0为标志位
  142. for(j=0,j_0=0;j_0<k;j_0++,j++)//进行k次交换
  143. {
  144. if(i==k&&f==0)//判断是否为中间行
  145. {
  146. j+=k;
  147. f=1;
  148. }
  149. x=a[i][j];
  150. a[i][j]=a[i+2*k+1][j];
  151. a[i+2*k+1][j]=x;
  152. }
  153. }
  154. //换B、D象限相关数字的位置
  155. if(k>=2)
  156. for(i=0;i<k-1;i++)//每行交换k-1个数
  157. for(j=0;j<2*k+1;j++)//从第0行到第2*k行交换
  158. {
  159. x=a[j][3*k+1+i];
  160. a[j][3*k+1+i]=a[2*k+1+j][3*k+1+i];
  161. a[2*k+1+j][3*k+1+i]=x;
  162. }
  163. }

3、双偶数阶魔方阵(n为偶数,且能被4整除)

一般规律:

  1. 用横线和竖线将n阶魔方阵均分为m个4*4的小魔方阵。
  2. n*n个数从小到大,从左到右,从上到下,依次填入方阵中,遇到4*4的小方阵的对角线不填(注:此位置不填的数不作为下一个位置填的数)
  3. n*n个数从小到大,从右到左,从下到上,依次填入方阵4*4的小方阵的对角线上,其他位置不填(注:此位置不填的数不作为下一个位置填的数)
  4. 将2、3两步得到的魔方阵合并为一个魔方阵,双偶数阶魔方阵排列完成。

642361606757
955541213515016
1747462021434224
4026273736303133
3234352928383925
4123224445191848
4915145253111056
858595462631

解决双偶数阶魔方阵的关键是要准确计算对角线

从左上到右下的对角线满足 line % 4 == row % 4

从右上到左下的对角线满足 ( line + row ) % 4 == 3

01234567
00347
12367
23478
336710
447811
5671011
6781112
77101114

代码实现:

  1. void double_even_number(int n)
  2. {
  3. int line,row;
  4. int t_1=1,t_2=n*n;//t_1为正向,t_2为逆向
  5. for(line=0;line<n;line++)
  6. {
  7. for(row=0;row<n;row++)
  8. {
  9. if(line%4==row%4||(line+row)%4==3)//判断是否为对角线
  10. a[line][row]=t_2;
  11. else
  12. a[line][row]=t_1;
  13. t_1++;
  14. t_2--;
  15. }
  16. }
  17. }

主函数如下:

  1. #include<stdio.h>
  2. #include<math.h>
  3. int a[100][100]={0};//将数组a中所有元素赋值为0
  4. int main()
  5. {
  6. int n,i,j;
  7. void odd_number(int n);
  8. void single_even_number(int n);
  9. void double_even_number(int n);
  10. printf("请输入“魔方阵 ”的参数n=");
  11. scanf("%d",&n);
  12. if(n%2==1)
  13. odd_number(n);
  14. else if(n%4==2)
  15. single_even_number(n);
  16. else if(n%4==0)
  17. double_even_number(n);
  18. printf("该“魔方阵 ”如下:\n");
  19. for(i=0;i<n;i++)
  20. {
  21. for(j=0;j<n;j++)
  22. printf("%4d",a[i][j]);
  23. printf("\n");
  24. }
  25. return 0;
  26. }
本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/article/detail/35244
推荐阅读
相关标签
  

闽ICP备14008679号