题目:四阶幻方
把1~16的数字填入4x4的方格中,使得行、列以及两个对角线的和都相等,满足这样的特征时称为:四阶幻方。
四阶幻方可能有很多方案。如果固定左上角为1,请计算一共有多少种方案。
比如:
1 2 15 16
12 14 3 5
13 7 10 4
8 11 6 9
以及:
1 12 13 8
2 14 7 11
15 3 10 6
16 5 4 9
就可以算为两种不同的方案。
请提交左上角固定为1时的所有方案数字,不要填写任何多余内容或说明文字。
分析:简单的回溯问题,16*16,规模有点大,剪枝时条件需要严谨一点,逐步排除不满足条件的情况,以提高运算效率。我是这样想的,16个格子,有几个格子处是可以判断的:填充到第8个格子时,判断前面两行;填充到第12个格子时,前面两行肯定满足条件了,此时判断第三行和前面任一行;填充到第13个格子时,前面三行已经满足,此时再判断下第一列和一个对角线;填充到14、15个格子时判断下列;填充到最后一个格子时,判断下最后一列、最后一行以及另一条对角线。
代码如下:
package 第六届决赛;
public class 四阶幻方 {
private static int count=0;
public static void main(String args[]){
int a[]=new int[16];
a[0]=1;
for(int i=1;i<16;i++)
a[i]=0;//初始化
fun(a,1);
System.out.print(count);
}
public static void fun(int a[],int n){
//填充第n个格子
if(n==16){
count++;
}else{
for(int i=2;i<=16;i++){
a[n]=i;
if(check(a,n))
fun(a,n+1);
}
}
}
public static boolean check(int a[],int n){
boolean f=true;
for(int i=0;i<n;i++){ //判重复
if(a[i]==a[n]){
f=false;
break;
}
}
if(n==7){//完成前面两行
int m=a[0]+a[1]+a[2]+a[3];
int m1=a[4]+a[5]+a[6]+a[7];
if(m!=m1)
f=false;
}
if(n==11){ //完成前面三行,此时前面两行是满足条件的
int m1=a[4]+a[5]+a[6]+a[7];
int m2=a[8]+a[9]+a[10]+a[11];
if(m1!=m2)
f=false;
}
if(n==12){ //行满足
int m2=a[8]+a[9]+a[10]+a[11];
int s=a[0]+a[4]+a[8]+a[12];
int x=a[3]+a[6]+a[9]+a[12];
if(m2!=s)
f=false; //验证第一列
if(m2!=x)
f=false; //验证第一个对角线
}
if(n==13){ //行满足
int m2=a[8]+a[9]+a[10]+a[11];
int s1=a[1]+a[5]+a[9]+a[13];
//int x=a[3]+a[6]+a[9]+a[12];
if(m2!=s1)
f=false; //验证第二列
}
if(n==14){ //行满足
int m2=a[8]+a[9]+a[10]+a[11];
int s2=a[2]+a[6]+a[10]+a[14];
//int x=a[3]+a[6]+a[9]+a[12];
if(m2!=s2)
f=false; //验证第二列
}
if(n==15){ //全部填充完
int s2=a[2]+a[6]+a[10]+a[14];
int s3=a[3]+a[7]+a[11]+a[15];
int x1=a[0]+a[5]+a[10]+a[15];
if(s2!=s3)
f=false;//验证最后一列
if(s2!=x1)
f=false;
}
return f;
}
}
答案是416