蓝桥杯-四阶幻方

标题:四阶幻方

把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的数字,每个节点逻辑上就是从这
	些数字来选择路线,比如1,后面选择2-15(到这是纯粹的回溯)。而这条路线受题目中的格子的
	 条件所约束,如每行=34,可以理解为递归了4层的和必须=34,这可以成为递归条件。
	 
	==由于这里复杂度大,要根据这些条件进行剪枝,剪枝时,要找到当前尽可能多的条件,再来比较可能的限制。 
	 如当前行的和>34,后面必定>34,所以不必再搜索, 
	 	if(current>34)return; //剪枝 
		if(j_temp==3&¤t+k!=34)continue;
		
	==还有要注意临界情况的处理,总之,回溯法对每一步骤要求清晰。 
*/ 

#include<iostream>
using namespace std;
int v[18];
int a[4][4];
__int64 ans;

//judge,若不符合列,对角线条件return 0,否则return 1 
int judge(){
	//列判断 
	for(int i=0;i<4;i++){
		int sum3=0;
		for(int j=0;j<4;j++){
			sum3+=a[j][i];
		}
		if(sum3!=34)return 0;
	}
	//对角线判断 
	int sum4=a[0][0]+a[1][1]+a[2][2]+a[3][3];
	if(sum4!=34)return 0;
	int sum5=a[0][3]+a[1][2]+a[2][1]+a[3][0];
	if(sum5!=34)return 0;
	return 1; 
}

void dfs(int i,int j,int current){
	if(i==3&&j==3){ 
		if(judge())
			ans++;
		return;
	}
	int i_temp,j_temp;//i_temp,j_temp为将要前进的格子的下标 
	if(j==3){
		i_temp=i+1;j_temp=0;
	}else if(j<3){
		i_temp=i;j_temp=j+1;
	}
	for(int k=2;k<=16;k++){
		//剪枝 
		if(current>34)return; 
		if(j_temp==3&¤t+k!=34)continue;
		if(!v[k]){//若前面未使用过数字 k,则进行复制,递归 
			v[k]=1;
			a[i_temp][j_temp]=k;
			if(j_temp<3)
				dfs(i_temp,j_temp,k+current);
			else
				dfs(i_temp,j_temp,0);
			//回溯时要特别注意还原一些变量。这里其实也可不执行a[i_temp][j_temp]=0; 
			//因为current总是记录当前行能递归的格子的当前总值,一旦能递归,由a[i_temp][j_temp]=k;覆盖原值 
			a[i_temp][j_temp]=0; 
			v[k]=0;
		}
	}
}

int main(){
	v[1]=1;
	a[0][0]=1;
	dfs(0,0,1);
	cout<<ans<<endl;
	return 0;
} 
//答案为:416


扫一扫,支持我一下^_^

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值