任意阶魔方阵算法的实现

  老师布置了一道c语言的题目:生成任意阶的魔方阵,通过阅读现有算法,作了自我实现,具体算法介绍可以参照:
    http://www.cnblogs.com/codingmylife/archive/2010/12/24/1915728.html   这个网址,也可参照百度百科,非常全面。
 魔方阵,古代又称“纵横图”,是指组成元素为自然数1、2…n的平方的n×n的方阵,其中每个元素值都不相等,且每行、每   列以及主、副对角线上各n个元素之和都相等。以下是代码,算法嵌入到注释中:

/*
reference from 
http://www.cnblogs.com/codingmylife/archive/2010/12/24/1915728.html
*/
#include<stdio.h>

/*
输出阵列
*/
int printA(int **magic,int n)
{  int i,j;
	if(magic==NULL)
	{
	printf("参数为空指针\n");
	return 0;
	}
     printf("输出结果:\n");
	 for(i=1;i<=n;i++)
	 {
		  //printf("......:\n");
		 for(j=1;j<=n;j++)
		 printf("%d\t", *(*(magic+i)+j));
		 printf("\n");
	 }
	 return 1;
}
/*
奇阶阵求法
奇数阶幻方最经典的填法是罗伯法。填写的方法是:

把1(或最小的数)放在第一行正中; 按以下规律排列剩下的(n×n-1)个数: 
1、每一个数放在前一个数的右上一格; 
2、如果这个数所要放的格已经超出了顶行那么就把它放在底行,仍然要放在右一列; 
3、如果这个数所要放的格已经超出了最右列那么就把它放在最左列,仍然要放在上一行; 
4、如果这个数所要放的格已经超出了顶行且超出了最右列,那么就把它放在前一个数的下一 

  行同一列的格内; 
5、如果这个数所要放的格已经有数填入,那么就把它放在前一个数的下一行同一列的格内。
*/
void Odd(int n)
 {
   //声明填充计数next ,二维矩阵magic
     int i,j;
     int **magic;
   //检查是否奇幻方	 
    if((n/2)*2==n)
    {
	   printf("Wrong method use!!\n");
	   return;
    }
    else
    {
   /*奇阶魔方阵生成算法*/
	   
      
		 magic = new int *[n+1];
		 for(i=1;i<=n;i++)
		 {
			 magic[i]=new int [n+1];
			 for(j=1;j<=n;j++)
				 magic[i][j]=0;
		 }
    
    //write 
	int fullFill(int **magic,int n,int next);
	fullFill(magic, n ,1);
      
	}//else
    printA(magic,n);
 
 }//endof Cardinal

/*
int fullFill()阶梯法填数组
***
*/
int fullFill(int **magic,int n,int next)
{  
	int nx,ny;
    int end=n*n+next-1; 
     
     nx=1;
	 ny=(n+1)/2;
     *(*(magic+nx)+ny)= next;
     
	 while(next<end)
	 {
		  
	    nx--;
		ny++;
		next++;
		if(nx==0&&ny!=(n+1))
			nx=n;
		else if(nx!=0&&ny==(n+1))
            ny=1;
		else if(nx==0&&ny==(n+1)|| *(*(magic+nx)+ny)!=0)
		{
		   nx=nx+2;
		   ny--;
		}
		 
         *(*(magic+nx)+ny)=next;
			  
	 }//while

  return 1;
}

/* --------
双偶阶阵求法void doubleEven()
对于n=4k阶幻方,我们先把数字按顺序填写。写好后,按4×4把它划分成k×k个方阵。
因为n是4的倍数,一定能用4×4的小方阵分割。
然后把每个小方阵的对角线,象制作4阶幻方的方法一样,对角线上的数字换成互补的数字,

就构成幻方
   */
 void doubleEven(int n)
 {
	int i,j,m,q;
	int next = 0;
	int  **magic;

    if((n/4)*4!=n)
	printf("Wrong method use!!\n");
	else
	{
	 magic=new int *[n+1];
	 for(i=1;i<=n;i++)
	 {
		 magic[i]=new int[n+1];
		 for(j=1;j<=n;j++)
			 *(*(magic+i)+j)=(++next);
	 }

     /* 4阶小方阵对角线求补 */
  for(m=1;m<=n;m+=4)
	 for(q=1;q<=n;q+=4)
	 {
     //@对角线1上元素求补
	  i=m;
	  j=q;
      while(i<=m+3&&j<=q+3)
	  {
	   *(*(magic+i)+j)=n*n+1-*(*(magic+i)+j);
	   i++;j++;
	  }

     //@对角线2上的元素求补
	  i=m;
	  j=q+3;
      while(i<=m+3&&j>=q)
	  {
	   *(*(magic+i)+j)=n*n+1-*(*(magic+i)+j);
	   i++;j--;
	  }
	 }//for for	 end   
	
	
	}//else end

  printA(magic,n);
 }


/*
 单阶偶阵void singleEven()
(1)把方阵分为A,B,C,D四个象限,这样每一个象限肯定是奇数阶。用罗伯法,依次在A

象限,D象限,B象限,C象限按奇数阶幻方的填法填数。
(2)在A象限的中间行、中间格开始,按自左向右的方向,标出k格。A象限的其它行则标出

最左边的k格。将这些格,和C象限相对位置上的数,互换位置。
(3)在B象限任一行的中间格,自右向左,标出k-1列。(注:6阶幻方由于k-1=0,所以不用

再作B、D象限的数据交换),
     将B象限标出的这些数,和D象限相对位置上的数进行交换,就形成幻方。
 */
void singleEven(int n)
{

  int k,i,j,m,x,next=1,temp;
  int **A;
  int **B;
  int **C;
  int **D;
   
      
	// @ printf("初始化二级指针");
	 A= new int *[n+1];
	 B= new int *[n+1];
	 C= new int *[n+1];
	 D= new int *[n+1];
     for(i=1;i<=n;i++)
	  {
	    A[i] = new int[n+1];
        B[i] = new int[n+1];
		C[i] = new int[n+1];
		D[i] = new int[n+1];
		for(j=1;j<=n;j++)
		{
			A[i][j]=0;
			B[i][j]=0;
			C[i][j]=0;
			D[i][j]=0;
		}
	  }
	   
  
    
  if(n%4!=0&&n%2==0)
  {
   k=n/2;    //每个小方阵的阶  n=2*k=2*(2m+1)=4m+2  
   m=(k-1)/2;//要向左或向右标记的元素个数k=2*m+1
   x=k/2+1;  //每个小方阵的中间行中间列
   
 /*@初始化
   四个象限的魔方阵*/
   fullFill(A,k,1);
   fullFill(D,k,k*k+1);
   fullFill(B,k,2*k*k+1);
   fullFill(C,k,3*k*k+1);
 
  
/*@交换元素**
*/
   for(i=1;i<=m;i++)
   {
	 //对中间行,包括中间元素向右标记m个元素,并交换A C对应位置
	  temp=C[x][x+i-1];
	  C[x][x+i-1]=A[x][x+i-1];
	  A[x][x+i-1]=temp;

	//除中间行外,其他行从中间格开始,向左标记m个元素(不包含中间),并交换A C

中的相应位置
	  for(j=1;j<=k;j++)
	  if(j!=x)
	  {
	  temp=C[j][x-i];
	  C[j][x-i]=A[j][x-i];
	  A[j][x-i]=temp;

	  }

     //从每一行的中间格开始向右标记m-1列,并交换B D对应位置
	  if(i<=m-1)
      for(j=1;j<=k;j++)
	  {
	     temp=B[j][x+i-1];
		 B[j][x+i-1]=D[j][x+i-1];
		 D[j][x+i-1]=temp;

	  }

    }
/*   
   printA(A,k);
   printA(B,k);
   printA(C,k);
   printA(D,k);
   */
 //@输出结果----------------------
   printf("输出结果:\n");
for(i=1;i<=k;i++)
{
   for(j=1;j<=k;j++)
	   printf("%d   ",A[i][j]);
   for(j=1;j<=k;j++)
       printf("%d   ",B[i][j]);

   printf("\n");

}
 for(i=1;i<=k;i++)
{
   for(j=1;j<=k;j++)
	   printf("%d   ",C[i][j]);
   for(j=1;j<=k;j++)
       printf("%d   ",D[i][j]);

   printf("\n");

}
  
  
 //end output---------------------
  }else
   printf("Wrong method use!!\n");

}

//--->>>>>程序入口<<<<<----
 int main()
{
  int n;
  for(;;)
  {
  printf("输入魔方阵阶数,回车结束:n=\n");
  scanf("%d",&n);

  if(n%2!=0)
  Odd(n);
  if(n%4==0)
  doubleEven(n);
  if(n%2==0&&n%4!=0)
  singleEven(n);
  printf("是否继续(0退出/1继续)?");
  scanf("%d",&n);
 if(n==0)
   return 0;

  }
  
  return 0; 
}

 


  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值