2017 软工第二次作业

Github

地址:https://github.com/deepYY/sudoku


PSP表格

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 60 60
Estimate 估计这个任务需要多少时间 30 60
Development 开发 720 720
Analysis 需求分析 (包括学习新技术) 120 480
Design Spec 生成设计文档 120 240
Design Review 设计复审 (和同事审核设计文档) 60 120
Coding Standard 代码规范 (为目前的开发制定合适的规范) 60 60
Design 具体设计 60 60
Coding 具体编码 60 60
Code Review 代码复审 60 60
Test 测试(自我测试,修改代码,提交修改) 120 360
Reporting 报告 10 10
Test Report 测试报告 10 10
Size Measurement 计算工作量 60 60
Postmortem & Process Improvement Plan 事后总结, 并提出过程改进计划 60 60
合计 1610 2300

解题思路

刚看到这题,因为要随机数独,所以我先去网上找了如何生成随机数的资料.然后我是想用二维数组存数独,然后从用随机数往里面依次从左到右,从上到下填数,在判断填入的数是否符合数独规则,符合就继续下一个,不符合就重新生成随机数.但发现刚开始填入没问题,但越到后面数独的规则就越来越束缚,所能填的数也越来越少,而且也会导致那个格只能填一个数,但填入那个数却不符合数独的情况存在.后来查阅数独这类算法的资料,发现数独回溯法,跟深度优先搜索一样,依次填下去,实在不行在回头重新填.在找资料的过程中也找到两篇很好的博客,一个是关于分治的思想来填入数独,将一个大的数独9*9的格,编号分成9个3*3的宫,先重数字1开始填到9个宫,边填边检查是否符合数独条件,这不仅省去了数独在一个宫的检查方式,而且在数字1和9的填入中也不需要回溯.我先是用这个方法实现随机数独,但后来因为有个固定一个数条件,我就用了我之前找资料时看到的另一篇博客的思想,是个用一个大小为9的一维数组来存1到9各不相同的随机数为一个随机序列,我就想将两者的方法结合,通过这组随机数来改变之前生成的随机数组从而满足题目要求.

参考博客:


设计实现

  • 用两个函数来当前判断填入的数是否符合数独的规则.
  • 用一个函数来将没填入的格全填入9.
  • 用一个函数通过回溯的方式来生成一个随机数独,用二维数组来存这个随机数独,这个函数有调用两个检查的函数.
  • 用一个函数来生个一组大小为9的随机序列
  • 用一个函数来改变生成的随机数独为满足题目要求的随机数独
  • 用一个函数来数独查重(添加)

代码说明

void creat_Sudoku(int num, int number) {									//建立数独、这里的num和number分别是要填的数和所填的块的编号
	int x, y, l_flag, r_flag;											        //x和y存随机的位置,l_flag和r_flag是判断当前的位置是否符合数独规则
	int	t = 0;														//记录重新随机的次数
	int last1 = -1, last2 = -1;												//上次的x和y的值用last1和last2来保存
	if (num == 9) {														//只剩9没填时,将格为0的全变为9
		Sdk();                                                                                
	}
	else {
		while (true) {
			x = rand() % 3 + 3 * (number / 3);								//跟据块的编号,随机生成位置(x,y)
			y = rand() % 3 + 3 * (number % 3);
			if (Sudoku[x][y] != 0) {										//当生成的位置有数时,重新随机,重新随机次数过多时,回溯
				t++;
				if (t == 8) {
					flag = 2;
					t = 0;
					return;
				}
				continue;
			}
			if (Sudoku[x][y] == 0) {
				if (last1 == x&&last2 == y) {								//当生成的位置没数,但一直是这个位置,回溯
					t++;
					if (t == 8) {
						flag = 2;
						t = 0;
						return;
					}
					continue;
				}
				last1 = x;
				last2 = y;
				Sudoku[x][y] = num;
				r_flag = check_row(x, y);
				l_flag = check_line(x, y);
				if (r_flag == 1 || l_flag == 1) {
					Sudoku[x][y] = 0;
					t++;
					if (t < 8)		continue;
					else {
						t = 0;
						flag = 2;
						return;
					}
				}
				if (r_flag == 0 && l_flag == 0) {
					if (number != 8) {
						creat_Sudoku(num, number + 1);										//填入的这个数满足数独条件,到下一个数
						if (flag == 2) {                                                                                                          //当发生回溯,重新生成随机数
							Sudoku[x][y] = 0;
							flag = 0;
							continue;
						}
						else break;
					}
					else {
						creat_Sudoku(num + 1, 0);											//填入的这个数满足数独条件,到下一个数
						if (flag == 2) {
							Sudoku[x][y] = 0;
							flag = 0;
							continue;
						}
						else break;
					}
				}
			}
		}
	}
}

测试运行

测试:

结果:


性能分析

从上图中可以看出,在创建数独的函数creat_Sudoku()和以及去改变数独的函数chang_Sudoku()所占用的比较小,占用较大的主要在于将数独输出到sudoku.txt的函数上,我本想在输出到txt文件上优化,但现在遇到一个问题,当把ofstream 定义到全局时sudoku.exe文件就会停止工作,还在寻找解决方案。

多谢助教的提醒,将数独一次性输出,果然在输出函数上有了很大的优化。


单元测试

原文地址:https://www.cnblogs.com/deepYY/p/7493520.html