九宫幻方
蓝桥杯DFS
问题描述
小明最近在教邻居家的小朋友小学奥数,而最近正好讲述到了三阶幻方这个部分,三阶幻方指的是将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
做法
int main()
{
//输入的同时,维护弹夹(0~9 10个数) 和 预设值
//开始暴力深搜
//边界条件:深搜到底后,检查是不是对的,不对就直接回溯,对的就保存之后再回溯
//通过将深度和9宫格的位置挂钩,来直接判断当前所在格子
//如果是预设 就直接深入,如果是要玩家填补的,就按照弹夹依次打出
//完毕,输出结果
}
代码
#include<iostream>
#include<algorithm>
#include<string>
#include<vector>
#include<cmath>
#include<string.h>
using namespace std;
int map[10][10]={0};//一开始就输入,后面用来频繁更新状态
bool clip[10];//弹夹,clip[3]=1表示数字3还没有被使用
//isYuShe[2][1]=1表示2行1列这个数不是玩家的目标
int isYuShe[10][10]={0};//即原本就有数 没让玩家填的地方
bool check(){//检查地图的当前状态,是不是九宫 题目要求的那种
//每一行的和都是相同
int sum=map[1][1]+map[1][2]+map[1][3]; //第一行的和
for(int i=2;i<=3;i++){
if(sum!=map[i][1]+map[i][2]+map[i][3])return false;
}
//每一行 每一列 的和都是相同
for(int j=1;j<=3;j++){
if(sum!=map[1][j]+map[2][j]+map[3][j])return false;
}
//每一行 每一列和 每一条对角线 的和都是相同
if(sum!=map[1][1]+map[2][2]+map[3][3] ||
sum!=map[1][3]+map[2][2]+map[3][1]) return false;
}
int cnt=0;//有多少种对的填补方法
int finalMap[10][10]={0};
void dfs(int deep){
//边界条件:深搜到底后,检查是不是对的,不对就直接回溯,对的就保存之后再回溯
if(deep==10){//如果深度为10,说明前9次 使得弹夹一定打空了
if(check()){
cnt++;
memcpy(finalMap,map,sizeof(map));
}
return;//回溯
}
//通过将深度和9宫格的位置挂钩,来直接判断当前所在格子
int myI=(deep-1)/3+1;//深度为1时,是1行1列,深度为4是2行1列
int myJ=(deep-1)%3+1;//(如果不把深度和位置挂钩,就要携带 很麻烦)
//如果是预设 就直接深入,如果是要玩家填补的,就按照弹夹依次打出
if(isYuShe[myI][myJ])dfs(deep+1);
else{
for(int i=1;i<=9;i++){
if(clip[i]==0)continue;
map[myI][myJ]=i;//打出
clip[i]=0;
dfs(deep+1);
//回溯 回来以后,重新装填该编号弹药
clip[i]=1;
map[myI][myJ]=0;
//依次选择 后面编号的弹药
}
}
}
int main()
{
//输入的同时,维护弹夹(0~9 10个数) 和 预设值
memset(clip,1,sizeof(clip));
for(int i=1;i<=3;i++){
for(int j=1;j<=3;j++){
cin>>map[i][j];
if(map[i][j]!=0){
isYuShe[i][j]=1;//该地区 原本就有数
clip[map[i][j]]=0;//用掉该编号的子弹
}
}
}
//开始暴力深搜
dfs(1);
//完毕,输出结果
if(cnt==1){
for(int i=1;i<=3;i++){
for(int j=1;j<=3;j++){
cout<<finalMap[i][j]<<" ";
}
cout<<endl;
}
}else{
cout<<"Too Many"<<endl;
}
return 0;
}
1464

被折叠的 条评论
为什么被折叠?



