蓝桥杯试题 历届试题 九宫幻方

蓝桥杯试题 历届试题 九宫幻方

问题描述
  小明最近在教邻居家的小朋友小学奥数,而最近正好讲述到了三阶幻方这个部分,三阶幻方指的是将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
  不能通过工程设置而省略常用头文件。

提交程序时,注意选择所期望的语言类型和编译器类型。

--------------

笨笨有话说:
  我最喜欢这类题目了。既然九宫幻方一共也没有多少,我就不辞辛劳地一个一个写出来好了。
  也不能太过分,好歹用个数组。
  
  -----------------------------------------------------------------------------------------------
  这个题目笨笨好像就是在提示我们在用暴力法解题,当然也可以暴力,但是我想用深搜的解法件此题做出来

这里我用一维数组代替一个二维,我感觉差不多的;a->代表我的输入的二维的九宫格,visited[i]代表i这个数字是否被遍历过,当然如果一开始就给出其相应的位置,那么当然它就是被遍历过,所以在我进行输入的时候,如果他的位置已经固定,那么就将其标记。b数组则代表如果恰为一个解,那么我就把该解存到b数组中,方便以后的输出。结束标记当然就是9个位置的数填完,即m == 10 结束,结束时进行判断,是否满足条件。

	if (a[m] != 0)
	{
		dfs(m + 1);
	}

这个地方就是我觉得比较好的地方,就是对已经输入的数字不变,继续填充下一个位置,就是固定了该数字的位置

a[i]上数字非0,那么就说明第i个位置题目已给,不需要再填充数字
visited[i] 表示数字i已经被用过,不管是题目所给还是我填充的过程中所用
这里一定要注意两者的区别,所以就有了

a[m] = 0;

这个代码,这个位置很重要,我一开始就是掉了这一行代码,找了半天错误,因为我们上面用到了固定位置那个代码,所以可能就因为这次保存的数据在下一次依然存在时误以为是不需要填充的位置,就跳转到下一个位置,所以这里如果仅仅时将visited置为0的话,那么a[m]还是存在,并且会对后续的使用产生影响,所以一定要保持初始状态的一致

#include 
using namespace std;
int  visited[10]; 
int a[10], sum = 0, b[10];
void dfs(int m)
{
	int i, j; 
	if (m == 10)
	{
		if (a[1] + a[2] + a[3] == a[4] + a[5] + a[6] && a[4] + a[5] + a[6] == a[7] + a[8] + a[9] && a[4] + a[5] + a[6] == a[1] + a[5] + a[9] && a[1] + a[5] + a[9] == a[3] + a[5] + a[7] && a[1] + a[4] + a[7] == a[2] + a[5] + a[8] && a[2] + a[5] + a[8] == a[3] + a[6] + a[9] && a[2] + a[5] + a[8] == a[1] + a[2] + a[3])//判断条件
		{
			sum++;
			for (i = 1 ; i <= 9 ; i++)
			{
				b[i] = a[i];
			}
			
		}
	}
	if (a[m] != 0)//如果该位置已有数字,那么填充下一个位置,保持该位置数字不变
	{
		dfs(m + 1);
	}
	else//如果该位置为0,即需要进行数字的填充
	{
		for (i = 1 ; i <= 9 ; i++)
		{
			if (!visited[i])
			{
				a[m] = i;
				visited[i] = 1;
				dfs(m + 1);
				visited[i] = 0;
				a[m] = 0;//这个位置很重要,我一开始就是掉了这一行代码,找了半天错误,因为我们上面用到了固定位置那个代码,所以可能就直接因为这次保存的数据在下一次依然存在时误以为是不需要填充的位置,就跳转到下一个位置,所以这里如果仅仅时将visited置为0的话,那么a[m]还是存在,并且会对后续的使用产生影响,所以一定要保持初始状态的一致
			}
		}
	}
}
int main()
{
	int i, num;
	for (i = 1 ; i <= 9 ; i++)
	{
		cin >> a[i];
		if (a[i])
		{
			visited[a[i]] = 1;
		}
	}
	dfs(1);
	if (sum == 1)
	{
		for (i = 1 ; i <= 9 ; i++)
		{
			cout << b[i] << " ";
			if (i % 3 == 0)
			{
				cout << endl;
			}
		}
	}
	else
	{
		cout << "Too Many";
	}
	return 0;
}

如有错误,麻烦指出!谢谢观看!

你可能感兴趣的:(蓝桥杯,c++,dfs,算法)