五阶幻方研究

     原以为奇数阶幻方中,正中间的方格应该填入数列中的中位数,例如在3阶幻方中,正中间的方格应该填入5,但是在5阶幻方中,这个假设就失效了,下面是具体的例子。

1

2

13

24

25

5

23

16

9

12

21

22

10

4

8

20

3

19

17

6

18

15

7

11

14

 

1

2

13

24

25

5

23

17

4

16

18

19

9

8

11

20

6

14

22

3

21

15

12

7

10

     正中间的单元格一个是10,一个是9,都不是13。

    下面的这个例子是从网上找到的五阶幻方求解的源程序,采用逐步搜索的方法,求得所有解。我最长运行了3小时,求得了大约29万种不同解,不知道全部有效解一共是多少?

#include "stdio.h"
#define LENGTH 10
#define SIZE LENGTH*LENGTH
int	a[LENGTH][LENGTH],b[SIZE],degree,number=0,max,sum;

int main()
{
int i=0,j=0,m,temp,n,x,k,y,h,z;
printf("please input a degree:");
scanf("%d",&degree);
max=degree*degree;
sum=(max+1)*degree/2;
for(i=1;i<=degree;i++)
{
b[i]=0;
//1-5标记为没有选中,因为0不是目标数字,所以i从1开始
//b[]可能代表某一行的5个数
for(j=0;j<degree;j++)
{
a[i-1][j]=0;
//目标数组全部置为0,行标从0开始,列标也从0开始

}
}
//全部赋0值
i=j=z=0;
while(1)
//大循环开始

{
temp=a[i][j];
a[i][j]=0;
//把a[i][j]读出来,赋值给temp,然后将a[i][j]置为0
//a[][]为目标数组
for(m=temp+1+z,z=0;m<=max;m++)
{
if(b[m]==0)
{
if(temp!=0)
{
b[temp]=0;
temp=0;
}
if(i<degree-2 && j<degree-2)
//是否进入第三行、第三列
{
if(i==degree-3)
//行判断,是不是第三行
{
for(n=0,x=0;n<i;n++)
{
x+=a[n][j];
}
x+=m;
//x为已知数的和
k=sum-x;
//K为剩余数的和

if(k>max+max-1 || (k==max+max-1 && (b[max]==1 || b[max-1]==1)))
//剩余的数字已无可能
{
continue;

}
if(k<3 || (k==3 && (b[1]==1 && b[2]==1)))
//剩余的数字已无可能
{
m=max+1;
break;
}
}
if(j==degree-3)
 //列判断,是不是第三列
{
for(n=0,x=0;n<j;n++)
{
x+=a[i][n];
//x为该行已选数字之和
}
x+=m;
//m为该行第三列待选数字
k=sum-x;
//某列已选好的数字求和,没选的数字求和
if(k>max+max-1 || (k==max+max-1 && (b[max]==1 || b[max-1]==1)))
//还剩2个数没有选,如果k值大于最大两个数之和,表示没有可能;如果等于最大两个数之和,但是最大两个数其中之一已经用过了,表示没有可能。
{
continue;
}
if(k<3 || (k==3 && (b[1]==1 && b[2]==1)))
//最小情况判断,比3还小不可能,等于3但是1,2其中之一已被选择,也不可能
{
m=max+1;
break;
}
}
//将M赋值给数组a,同时标记数组b,该数字已使用
a[i][j]=m;
b[m]=1;
j++;
break;
}
if(j==degree-2)
//该行已经选了3个数,准备选第四个数
{
for(n=0,x=0;n<j;n++)
{
x+=a[i][n];
//前面的数求和
}
x+=m;
//和值加入dm
k=sum-x;
//剩余的值
if(k>0 && k<=max && m!=k && b[k]==0)
//剩余的值在最大和最小之间,m与k不相等,k值没有被选过
{
a[i][j]=m;
b[m]=1;
a[i][j+1]=k;
b[k]=1;
//最后2个数字,一起完成赋值
if(i<degree-2)
//如果还剩超过2行,则进入下一行
{

i++;
j=0;
break;
}
}
else
{
if(i==degree-2 && j==1)
{
j--;
b[a[i+1][j]]=0;
a[i+1][j]=0;

break;
}
else
{
continue;
}
}
}
if(i==degree-2)
{
//还剩2行
for(n=0,x=0;n<i;n++)
{
x+=a[n][j];
}
x+=m;
k=sum-x;
//前几行求和,另外得出剩下几行的和
if(k>0 && k<=max && m!=k && b[k]==0)
{
//k的值在最大]、最小之间,m、k对应的值没有被用过
if(j<degree-2)
{
if(j==0)
{
for(n=0,x=degree-1,y=0;n<i;n++)
{
y+=a[n][x--];
//对角线求和
}
y+=k;
h=sum-y;
//对角线已选值的和,以及剩余的值的和
if(h>0 && h<=max && h!=k && h!=m && b[h]==0)
{
//对角线的判断
a[i][j]=m;
b[m]=1;
a[i+1][j]=k;
b[k]=1;
z=h-1;
//该行,和下一行的值复制
j++;
break;
}
else
{
continue;
}
}
if(j==1)
{
for(n=0,x=degree-1,y=0;n<i;n++)
{
y+=a[n][x--];
}
y+=(a[degree-1][0]+m);
if(y!=sum)
{
//值不满足65,重新归零
b[a[degree-1][0]]=0;
a[degree-1][0]=0;
j--;
break;
}
}
a[i][j]=m;
b[m]=1;
a[i+1][j]=k;
b[k]=1;
j++;
break;
}
else if(j==degree-2)
{
for(n=0,x=0;n<=i;n++)
{
x+=a[n][n];
}
h=sum-x;
if(h>0 && h<=max && h!=m && h!=k && b[h]==0)
{
for(n=0,y=0;n<=j;n++)
{
y+=a[n][degree-1];
}
if(y==x)
{
for(n=0,y=0;n<i;n++)
{
y+=a[degree-1][n];
}
y+=k;
if(y==x)
{
a[i+1][j]=k;
b[k]=1;
a[i][j]=m;
b[m]=1;
a[++i][++j]=h;
b[h]=1;
}
else
{
continue;
}
}
else
{
continue;
}
}
else
{
b[a[i][j+1]]=0;
a[i][j+1]=0;
b[a[i][j]]=0;
a[i][j]=0;
if(j==1)
{
b[a[i+1][j-1]]=0;
a[i+1][j-1]=0;
j--;
break;
}
else
{
continue;
}
}
}
}
else
{
if(j==1)
{
//这个判断好像无效
if(j==degree-2)
{
b[a[i][j+1]]=0;
a[i][j+1]=0;
}
b[a[i][j]]=0;
a[i][j]=0;
j--;
b[a[i+1][j]]=0;
a[i+1][j]=0;
break;
}

if(j==degree-2)
{
b[a[i][j]]=0;
a[i][j]=0;
b[a[i][j+1]]=0;
a[i][j+1]=0;
//某列两个数值归0
}
continue;
}
}
if(i==degree-1 && j==degree-1)
{
//已经到达第5行、第五列
for(k=0;k<degree;k++)
{
for(h=0;h<degree;h++)
{
//满足条件的结果输出
printf("%4d",a[k][h]);
}
printf("\n");
}
printf("\n");

number++;
printf("num=%5d\n",number);

if(number==100)
{
getchar();
getchar();
}
for(k=degree-2;k<degree;k++)
{
for(h=1;h<degree;h++)
{
b[a[k][h]]=0;
a[k][h]=0;
//第四行、第五行归0
}
}
b[a[degree-1][0]]=0;
a[degree-1][0]=0;
//第五行第一列归0
i--;
j=0;
break;
}
}
}
if(m>max)
{
//超出理论范围
if(temp!=0)
{
b[temp]=0;
}
if(j==0 && i>0)
{
i--;
j=degree-1;
b[a[i][j]]=0;
a[i][j]=0;
j--;
}
else if(j>0)
{
j--;
b[a[i+1][j]]=0;
a[i+1][j]=0;
}
else if(i==0 && j==0)
{
break;
}
}
}
printf("the total number is %d\n",number);
//结果输出

return 0;
}
发布了31 篇原创文章 · 获赞 5 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/ccozkf/article/details/81091499