小明最近在教邻居家的小朋友小学奥数,而最近正好讲述到了三阶幻方这个部分,三阶幻方指的是将 1∼9 不重复的填入一个 3×3 的矩阵当中,使得每一行、每一列和每一条对角线的和都是相同的。
三阶幻方又被称作九宫格,在小学奥数里有一句非常有名的口诀:“二四为肩,六八为足,左三右七,戴九履一,五居其中”,通过这样的一句口诀就能够非常完美的构造出一个九宫格来。
4 9 2
3 5 7
8 1 6
有意思的是,所有的三阶幻方,都可以通过这样一个九宫格进行若干镜像和旋转操作之后得到。
现在小明准备将一个三阶幻方(不一定是上图中的那个)中的一些数抹掉,交给邻居家的小朋友来进行还原,并且希望她能够判断出究竟是不是只有一个解。
而你呢,也被小明交付了同样的任务,但是不同的是,你需要写一个程序~
输入格式:
一个 3×3 的矩阵,其中为 0 的部分表示被小明抹去的部分。数据保证给出的矩阵至少能还原出一组可行的三阶幻方。
输出格式:
如果仅能还原出一组可行的三阶幻方,则将其输出,否则输出 "Too Many"。
输入样例
0 7 2
0 5 0
0 3 0
输出样例:6 7 2
1 5 9
8 3 4
我的思路:其实看到这道题,还是觉得该用爆搜,题目说每一种三阶幻方都由下边这个原始幻方旋转或镜像操作得来,那我就直接爆搜,一种幻方有镜像和旋转两种操作,将已知的可行的幻方镜像后判断是否满足,满足则ans+1,然后又将幻方旋转,得到另一个幻方,继续判断,旋转四次会变为原来的幻方,就重复了,这就是结束条件(注意,一个幻方镜像生成的新幻方不需要再旋转生成新幻方B,因为后边会有幻方通过镜像和旋转生成幻方B,如果将镜像旋转就会有数据重复)
4 9 2
3 5 7
8 1 6
代码:
#include<bits/stdc++.h>
using namespace std;
int a[3][3]={{4,9,2},{3,5,7},{8,1,6}};
int target[3][3];
int ans=0;
int b[3][3];
bool check(int a[][3]){for(int i=0;i<3;i++){for(int j=0;j<3;j++){if(target[i][j]!=0&&target[i][j]!=a[i][j]){return false;}}}return true;
}
void counter(int a[][3]){if(check(a)){ans+=1;if(ans==1){for(int i=0;i<3;i++){for(int j=0;j<3;j++)b[i][j]=a[i][j];}}}
}
void dfs(int a[][3],int count){if(count==4)return;counter(a);//镜像int temp[3][3]; for(int i=0;i<3;i++){for(int j=0;j<3;j++)temp[i][j]=a[i][2-j];}counter(temp);//旋转 for(int i=0;i<3;i++){for(int j=0;j<3;j++){temp[i][j]=a[2-j][i];}}dfs(temp,count+1);
}
int main(){for(int i=0;i<3;i++)for(int j=0;j<3;j++)cin>>target[i][j];dfs(a,0);if(ans==1){for(int i=0;i<3;i++){for(int j=0;j<3;j++)cout<<b[i][j]<<" ";cout<<endl;}}else cout<<"Too Many";
}
不过,我看了别人的题解,他直接将幻方的所有可能写了出来!!!然后直接一一判断是否与输入相符即可(因为可能的幻方好像也就八个,很容易列出来,这算是我没想到的点了)