第三次软件工程实践作业

我的GitHub:mmbhwhh

PSP

PSP 预估耗时(小时) 实际耗时(小时)
计划 2 3
估计这个任务需要多少时间 16 20
开发 1 2
需求分析 (包括学习新技术) 2 2
生成设计文档 2 3
设计复审 3 3
具体设计 2 3
具体编码 3 5
代码复审 3 3
测试(自我测试,修改代码,提交修改) 1 2
报告 2 3
过程改进计划 1 2
总计 22 31

思考

开始拿到题目的时候,以为是我想象中的数独,就简单的想着只要把每个已经确定的数对它当前所在的行、列、宫格的影响扩散出去,题目又说给的数独都是唯一解的,这更加让我确信用我的思路可以解出来,然后就试了试。

刚开始的思路

大体和第一位交作业的莫多同学一样,就是对数独遍历两次,第一次找到入口(因为题目说测试的数据都是唯一解),找到一个确定的点,然后将它的影响扩散给行、列、宫格,最终就会将整个表格填满。写了很久的代码,却发现我的思路只能填写一部分数据,没玩过数独的我还是太嫩了,后面冷静下来思考一番,如果数独有这么简单还叫什么数独呢,从我的那些错误的数据我知道了,尽管一个数独只有一个解,但是它也不一定可以用逻辑直接确定全部的值,因为我从我错误的代码打出来的错误结果显示,没填的那部分数据的确不能确定,必须要填入数值进去试探,虽然填的数字合法,但是解不出来。这结果让我原地自闭。

第二次想法

经历了上次的教训,索性直接用暴力的办法解这道题。思路就是从第一个格子一直找到最后一个格子,如果找到了空格子,那就给它赋上合法的数值,然后继续找,如果找不到了就出现了两种情况。一是已经填完了,结果出来了,并且它是合法的也就是它的解了;二是,找不到合法的值了,但是它却还是空着的,说明前面赋的值不对,此时再回去改,直到正确为止。代码如下:

check(u,i)函数是检测在u(把宫格的格子编号,从左上角为起始点一直到右下角,例如9宫格就有1、2、3...........80、81的编号)的位置,填入i合不合法

bool check(int u, int t)
{
	int x, y;
	x = (u - 1) / type + 1;
	y = (u - 1) % type + 1;//找到u这个位置的坐标
	for (int i = 1; i <= type; i++)
	{
		if (gg[x][i] == t && i != y)	return false;
		if (gg[i][y] == t && i != x)   return false;

	}//判断这个位置填入的数会不会与行和列冲突

	if (type == 4 || type == 6 || type == 8 || type == 9)
	{
		int xs, ys;
		int beginx, beginy;//当前坐标所在宫格的左上角坐标,可当做起始坐标
		switch (type)//判断宫格的规模
		{
		case 4:
			xs = 2;
			ys = 2;
			break;
		case 6:
			xs = 2;
			ys = 3;
			break;
		case 8:
			xs = 4;
			ys = 2;
			break;
		case 9:
			xs = 3;
			ys = 3;
			break;
		}
		int flogx = xs;
		int flogy = ys;//flogx和flogy只是待会下面用到的循环次数
		beginx = (x - 1) / xs * xs + 1;
		beginy = (y - 1) / ys * ys + 1;
		for (int i = beginx; flogx > 0; flogx--, i++)
		{

			for (int j = beginy; flogy > 0; flogy--, j++)
			{
				if (t == gg[i][j] && (x != i || y != j))	return false;
			}
			flogy = ys;
		}
		flogy = xs;
	}//判断此位置填入的数会不会与宫格里的冲突

	return true;//能走到这里说明填的数合法

}

上面的check函数会在dfs函数中用到,dfs的作用就是搜索

bool dfs(int u)
{
	if (u > type*type)	return true;//迭代到编号以外,说明前面填的数都是合法的
	int x, y;
	x = (u - 1) / type + 1;
	y = (u - 1) % type + 1;//给它坐标化
	if (gg[x][y])	return dfs(u + 1);//如果这个位置有数字,就去下一个点
	else {
		for (int i = 1; i <= type; i++)
		{
			if (check(u, i))
			{

				gg[x][y] = i;
				if (dfs(u + 1))return true;
				gg[x][y] = 0;
			}
		}//这个位置还没填入数据,就随便给它一个值,然后再执行下一个点,如果下一个点不可以了就会回来这个点重新赋值
		return false;
	}
}

测试结果


性能测试

posted @ 2019-09-25 20:41  猫猫不喝哇哈哈  阅读(171)  评论(3编辑  收藏  举报