高级软件工程第二次作业——个人项目实战:数独

第二次作业——个人项目实战

1).项目地址
github地址:https://github.com/xiezhe124/sudoku
使用语言:c++
运行环境:WIN10
开发平台:Visual Studio Professional 2017 15.3.5
2).解题思路
其实在我看到第二次作业已经发布的时候,我的内心是极其崩溃的,因为我前一天才赶着在假期开始之前把第一次作业做完,第二次作业就已经悄无声息的来到了我的面前。在我第一次看到这个题时,这个题目给我的感觉是“应该”不难。我第一时间想到的是这个题目需要三个判断函数,用来满足填入数字的规则,即同一行无重复,同一列无重复,同一九宫格无重复。但我那时一直有一个很大的疑惑,即这三个函数如何实现一次性判断无重复。后来发现我对这个题目的理解还停留在一种“静态”的思维,即一种填完之后再判断正确性的思维当中。之后我开始通过搜索引擎查找了关于“数独”的很多题目。其中有很多方法有参考价值,如最基本的单个填写再判断。生成随机行之后做置换等等。其中有一种方法比较有趣,即利用一个填写好的数独来进行变换,得到其他数独。受上述方法启发,我决定使用先填写一个子块再填写其余块的方法来实现数独的生成。
3).设计实现
采用一个静态二维数组来实现这个9*9的宫格,其中由题目所设,宫格中的数字为1-9,且行不重复,列不重复,九宫格不重复。也就是说,每行每列每个九宫格都是1-9的组合。数独每填完一个,就循环输出一个数独组合。然后初始化棋盘。上述都是基本的步骤,最重要的步骤是填入方法。在初始化过的棋盘中,生成不重复的随机数字来填写第一个九宫格。然后循环填写后续九宫格。在填写不进去时,尝试其他随机组合,但有可能现在的组合已经是无解的,所以设置一个尝试次数用来防止程序陷入死循环中。这里将其设置为100,即尝试填写100次失败之后就更换第一个九宫格中的随机组合。
4).代码说明
主函数部分
···

int C = atoi(argv[argc - 1]);
answerout.open("sudoku.txt");
if (C >0)
{
	bool back;
	int TryTimes = 0;
	srand((unsigned)time(NULL)); 
	int i = 0;
	while(i < C)//数独输出循环
	{
		back = false;
		if (TryTimes > 0&&TryTimes<100)//尝试次数较少
		{
			InitRest(answer);
		}
		else if (TryTimes==0)//开始状态
		{
			InitAll(answer);
			SubBuild(answer, 0);
		}
		else if(TryTimes>=100)//尝试次数大于100次后变更第一个九宫格组合
		{
			InitAll(answer);
			SubBuild(answer, 0);
		}
		for (int j = 1; j < 9; j++)//尝试构建后续八个九宫格
		{
			bool success = SubBuild(answer, j);
			if (!success)
			{ 
				back = true;
				break;
			}
		}
		if (back)//构建失败,尝试次数加一,根据尝试次数选择策略
		{
			TryTimes++;
		}
		else//构建完成,输出数独
		{
			for (int x = 0; x < 9; x++)
			{
				for (int y = 0; y < 9; y++)
				{
					answerout << answer[x][y] << ' ';
				}
				answerout << endl;
				if (x == 8)
					answerout<< endl;
			}
			TryTimes = 0; 
			i++;
		}
	}
	answerout.close();
}
//错误输出
else cout << "Please input a natural number" << endl;
return 0;

···
5).测试运行


6).性能分析
使用VS自带的性能探查器中的CPU采样分析方法,输入为5000.得到如图报表

使用VS自带性能探查器中的监测分析方法,输入为1000,得到如下报表

两种分析方法使用后,可知程序在构建九宫格时所消耗的时间和资源最多。所以可以尝试减少构建九宫格所需的时间和资源,最直接的方式便是减少尝试次数,由于题目的要求只是生成指定数量的数独,对于一初始九宫格和其后续可能存在无解情况,我们可以控制其尝试次数以求获得更多的组合来进行有意义的尝试,而减少对一无解问题的尝试。还有一点便是优化“放弃”该组合并初始化的后续九宫格的退回范围,即尝试次数过多后只初始化最后两个九宫格,如不行,再初始化三个,依次类推。由于时间有限,只对减少尝试次数这一优化方法进行了探索。发现在减少尝试次数的同时,程序有可能放弃本来有效的解,尤其是在尝试次数过低时,也就是说。这个尝试次数应该存在一个近似最优的值。
下图为函数耗时和函数调用次数

7).PSP

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 60 100
· Estimate · 估计这个任务需要多少时间 60 100
Development 开发 600 730
· Analysis · 需求分析 (包括学习新技术) 60 200
· Design Spec · 生成设计文档 60 10
· Design Review · 设计复审 (和同事审核设计文档) 0 0
· Coding Standard · 代码规范 (为目前的开发制定合适的规范) 30 0
· Design · 具体设计 60 100
· Coding · 具体编码 200 300
· Code Review · 代码复审 120 60
· Test · 测试(自我测试,修改代码,提交修改) 60 60
Reporting 报告 160 100
· Test Report · 测试报告 120 50
· Size Measurement · 计算工作量 20 10
· Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划 20 40
合计 820 930
posted @ 2017-10-08 21:21  解哲  阅读(203)  评论(0编辑  收藏  举报