历届试题 九宫幻方
时间限制:1.0s 内存限制:256.0MB
问题描述
小明最近在教邻居家的小朋友小学奥数,而最近正好讲述到了三阶幻方这个部分,三阶幻方指的是将1~9不重复的填入一个3*3的矩阵当中,使得每一行、每一列和每一条对角线的和都是相同的。
三阶幻方又被称作九宫格,在小学奥数里有一句非常有名的口诀:“二四为肩,六八为足,左三右七,戴九履一,五居其中”,通过这样的一句口诀就能够非常完美的构造出一个九宫格来。
4 9 2
3 5 7
8 1 6
有意思的是,所有的三阶幻方,都可以通过这样一个九宫格进行若干镜像和旋转操作之后得到。现在小明准备将一个三阶幻方(不一定是上图中的那个)中的一些数抹掉,交给邻居家的小朋友来进行还原,并且希望她能够判断出究竟是不是只有一个解。
而你呢,也被小明交付了同样的任务,但是不同的是,你需要写一个程序~
输入格式
输入仅包含单组测试数据。
每组测试数据为一个3*3的矩阵,其中为0的部分表示被小明抹去的部分。
对于100%的数据,满足给出的矩阵至少能还原出一组可行的三阶幻方。
输出格式
如果仅能还原出一组可行的三阶幻方,则将其输出,否则输出“Too Many”(不包含引号)。
样例输入
0 7 2
0 5 0
0 3 0
样例输出
6 7 2
1 5 9
8 3 4
数据规模和约定
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 1000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。
注意:
main函数需要返回0;
只使用ANSI C/ANSI C++ 标准;
不要调用依赖于编译环境或操作系统的特殊函数。
所有依赖的函数必须明确地在源文件中 #include <xxx>
不能通过工程设置而省略常用头文件。
提交程序时,注意选择所期望的语言类型和编译器类型。
--------------
笨笨有话说:
我最喜欢这类题目了。既然九宫幻方一共也没有多少,我就不辞辛劳地一个一个写出来好了。
也不能太过分,好歹用个数组。
// 这道题不难,关键在于剪枝,不剪枝的话,应该只能过70%左右
#include<set>
#include<map>
#include<list>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<bitset>
#include<iomanip>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#define eps (1e-8)
#define MAX 0x3f3f3f3f
#define u_max 1844674407370955161
#define l_max 9223372036854775807
#define i_max 2147483647
#define re register
#define pushup() tree[rt]=max(tree[rt<<1],tree[rt<<1|1])
#define nth(k,n) nth_element(a,a+k,a+n); // 将 第K大的放在k位
#define ko() for(int i=2;i<=n;i++) s=(s+k)%i // 约瑟夫
#define ok() v.erase(unique(v.begin(),v.end()),v.end()) // 排序,离散化
#define Catalan C(2n,n)-C(2n,n-1) (1,2,5,14,42,132,429...) // 卡特兰数
using namespace std;
inline int read(){
char c = getchar(); int x = 0, f = 1;
while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
while(c >= '0' & c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
typedef long long ll;
const double pi = atan(1.)*4.;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3fLL;
const int M=63;
const int N=1e5+5;
int n=0,a[5][5],v[10],b[10],p=0,sum=0,c[5][5];
bool fun(){
int ans=(a[0][0]+a[0][1]+a[0][2]);
if(ans==(a[1][0]+a[1][1]+a[1][2])
&&ans==(a[2][0]+a[2][1]+a[2][2])
&&ans==(a[0][0]+a[1][0]+a[2][0])
&&ans==(a[0][1]+a[1][1]+a[2][1])
&&ans==(a[0][2]+a[1][2]+a[2][2])
&&ans==(a[0][0]+a[1][1]+a[2][2])
&&ans==(a[0][2]+a[1][1]+a[2][0]))
return true;
return false;
}
map<int,int>mapp;
void dfs(int num){
if(sum>2) return ; // 剪枝1
for(int i=0;i<3;i++){ ------ // 剪枝2,每行,列,对角线和应该为15
int cut=0,leap=0; .
for(int j=0;j<3;j++){ .
if(a[i][j]==0){
leap=1;
break;
}
cut+=a[i][j]; .
} .
if(!leap&&cut!=15)
return ;
}
for(int i=0;i<3;i++){
int cut=0,leap=0; .
for(int j=0;j<3;j++){ .
if(a[j][i]==0){
leap=1;
break;
}
cut+=a[j][i];
}
if(!leap&&cut!=15) .
return ; .
}
int cut=0,leap=0;
for(int i=0;i<3;i++){
if(a[i][i]==0){ .
leap=1; .
break;
}
cut+=a[i][i];
}
if(!leap){
if(cut!=15)
return ; '
} .
cut=0,leap=0;
for(int i=0;i<3;i++){
if(a[i][2-i]==0){
leap=1;
break;
}
cut+=a[i][2-i]; .
} .
if(!leap){
if(cut!=15)
return ; .
} -------
if(num==n){
if(fun()){
int ans=0;
for(int i=0;i<3;i++)
for(int j=0;j<3;j++){
ans=ans*10+a[i][j];
c[i][j]=a[i][j];
}
if(!mapp.count(ans)){
mapp[ans]=1;
sum++;
}
}
return ;
}
for(int j=0;j<3;j++){
for(int k=0;k<3;k++){
if(a[j][k]==0){
for(int i=0;i<p;i++){
if(v[b[i]]) continue;
v[b[i]]=1;
a[j][k]=b[i];
dfs(num+1);
a[j][k]=0;
v[b[i]]=0;
}
}
}
}
}
int main(){
for(int i=0;i<3;i++)
for(int j=0;j<3;j++){
scanf("%d",&a[i][j]);
if(a[i][j]==0)
n++;
else{
v[a[i][j]]=1;
}
}
for(int i=1;i<=9;i++){
if(v[i]) continue;
b[p++]=i;
}
dfs(0);
if(sum==1){
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
printf("%d ",c[i][j]);
}
printf("\n");
}
}
else
printf("Too Many\n");
return 0;
}