Sudoku 个人项目1

Github项目地址:Github


项目相关要求

  • 随机构造出N个不重复的已解答的数独棋盘(0 < N <= 1000000)
  • 在生成数独矩阵时,左上角的第一个数为:(学号后两位相加)% 9 + 1
  • 相对路径生成sudoku.txt文件,结果输出到该文件

工具清单

  • 编程语言:C/C++
  • 编程IDE:Visual Studio 2017
  • 源代码管理平台:Github

解题过程

  刚看到题目的时候,是有点懵的,主要还是时间久了,对代码生疏了,也没有大佬的水准看一眼题目就有各种思路出来。思路也是慢慢才有一些的,想到的方法就是很暴力的,一个一个的判断填入,百度上说的也基本都是回溯方法。其实包括到现在,我代码的思路也是差不多的,只是在一些细节部分调整改动的多些。可能我出现的问题都不那么高大上,但都是一步步写代码的过程中所遇到的。

  首先,简单的输出问题。在很low的版本的时候,就想先试试一些细节和最后数独棋盘的输出,结果棋盘输出都成了问题。这真的就只能怪自己马虎,浪费了很多不该浪费的时间,就很生气了。。。(其实这个问题根本不算是困难,但就是想写出来,当做一个提醒!因为真的很浪费时间。。)

  接着,就是处理随机性的问题了。基于最先的直白暴力的做法,然后自己脑子都没拐拐弯,就直接采用了rand()函数来产生随机数,加点小操作来产生随机的1-9的数字,为了这个rand()函数还要用srand(seed)设置随机数种子。之后又是因为这个函数跟循环较上了劲,因为srand(seed)函数不能够放在循环内(百度了解的).
  考虑到没办法保证9次随机产生的1-9数能不重复的,所以次数问题卡了很久。然后就想为什么不先把1-9的数先确定(次数也就确定了),通过随机变换位置来到获得随机且不重复的数呢?所以就改用了数组arr[],初始存入9个数,然后又学习了一个好像很厉害的新函数random_shuffle(&arr[0],&arr[8]),能够随机打乱数组(来自舍友的分享)。

  到此,生成N个随机数独棋盘是没有问题了,就是在加上一些命令参数和文件输出的要求,整体就差不多完成了。


关键代码

  • 定义数独棋盘为二维数组map[9][9],bool型的参数m用于待填入时的临界判断,初始为false

  • 主函数外,代码中有五个函数:
      void set()赋初值函数
      bool check(string str)检查部分指令
      void fileoutput()文件输出
      bool judge(int k, int t)对待填入数字判断
      void insert(int k)填入

  • 承担了比较大的任务,代码如下:

//根据判断情况确定是否填入
void insert(int k)
{
	int row, col;
	row = k / 9;
	col = k % 9;
	if (k == 81)     //按格走的范围在0-80,若超过则退回
	{
		m = true;
		return;
	}
	if (map[row][col] != 0)
		insert(k + 1);
        else
	{
		if (k % 18 == 0)    //每个数独局面要5次随机
			random_shuffle(&(arr[0]), &(arr[9])); //随机打乱数组arr[]
		for (int i = 0; i<9; ++i) 
		{
			if (judge(k, arr[i]))	//允许插入
			{
				map[row][col] = arr[i];
				insert(k + 1);
				if (m)
					return;
				map[row][col] = 0;    //如果找不到可插入的值则恢复初值0
			}
		}
	}
}
//判断准备填入的数值是否符合要求
bool judge(int k, int t)
{
	int row, col;
	row = k / 9;	//取行值
	col = k % 9;	//取列值
	for (int j = 0; j < 9; ++j)	//对同行异列进行判断
		if (map[row][j] == t)
			return false;
	for (int i = 0; i < 9; ++i)	//对同列异行进行判断
		if (map[i][col] == t)
			return false;
	int a, b;
	a = row / 3 * 3;	//确定所在3*3九宫格的首位map[a][b]
	b = col / 3 * 3;
	for (int i = a; i < a + 3; ++i)	//对所在3*3九宫格进行判断
		for (int j = b; j < b + 3; ++j)
			if (map[i][j] == t)
				return false;
	return true;
}

测试

1、 运行测试

  •   命令行报错及正常运行测试结果截图如下:

  
  

2、效能分析

  •   最初版本的时间问题就比较尴尬了,那速度不敢恭维。。。所以,在阅读《构建之法》的第二章内容后,也看到了老师对项目测试要求的一些内容。我个人觉得效能分析比单元测试简单些,就先去做了效能分析。
  •   在最原始的版本,当时只测试了N=1000时的情况(当时没注意,用的是Debug版本的),截图如下:

  
  
  

  •   上面有些东西都不知道是啥,主要就看了几个函数的情况,主要的消耗都在调用上了。

  •   另外random_shuffle()函数相对于其他几个定义的函数,其自身的使用还是比较频繁的。我曾尝试改为生成一个数独棋盘就用同一个随机数组,通过计算发现这种情况下所能产生的不重复棋盘数仅为9!=362880个,对于1000000的测试数据来说,必然会有重复的棋盘。因此,我将调用次数改为一个棋盘需用三个随机数组,我计算的结果应该是有A39!=9!×(9!-1)×(9!-2)个数独棋盘。在保证随机数独棋盘数目足够的前提下,减少了对这个函数的使用。

  •   中间改进的版本还有两个,然而效能分析的时候却无法显示数据。。。
      (大概只有我这个特例吧。。。有借舍友的电脑尝试过,一样的无法显示,我们使用的都是VS 2017社区版,有让同学帮忙用VS 2015试过,也不行。。。有查过百度,却没有查到类似的问题,所以至今原因不明!)

  •   “无法显示数据”的情况截图如下:
      测试数据N为100000(Release版本):
      (因为中途有换过主题颜色,导致上下图片颜色的区别,但确实是自己的图)

  

  因为这个问题,我基本都是通过诊断时间大概判断的。。。

  最终的这个测试版本相对于之前的版本改进了输出。原先使用C++文件流的方法,之后在舍友那得知,在她的效能分析中这种输出方法占了近一半的时间,所以我也跟着做了改动。改为了更有效的重定向输入输出流的方法。

  •   这个最终版本我有再发给同学再尝试效能分析,居然可以。。。可我自己的电脑上依然不行!!!所以下列图片是同学帮忙截的图:
      测试数据N为100000(Release版本):

  
  


我的收获

  总的来说,这次的个人项目体验总结就是很紧张刺激。其实遇到的问题有很多,包括VS和Github的使用问题,都是第一次使用,特别VS给我留下了“深刻印象”,那个效能分析无法显示数据的坑也不知道该怎么填上,有点小无奈。
  这次的个人项目中的测试方面,我目前只做了效能分析(连效能分析都不能算完整)。因为时间比较赶,晚上的时间就来赶博客了(Markdown的使用还在边用边学中,加上有点调整版面的小强迫症,速度慢了些),单元测试就没弄,有点可惜。很多工具,和测试方法都是第一次从《构建之法》书中或是一些方法链接了解的。这次通过这个项目,接触了很多工具,但一个小小的个人项目也只是触及皮毛而已,接下去相信会学习到更多的。
  这几天宿舍里的学习氛围极强,每个人都在努力敲敲写写,每次也都想把程序的运行速度再提高一些,再一些,每一次进步都有事一份动力,所以继续加油,然后我去再赶赶单元测试吧。。。


PSP

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划
· Estimate · 估计这个任务需要多少时间 20 30
Development 开发
· Analysis · 需求分析 (包括学习新技术) 60 100
· Design Spec · 生成设计文档 50 50
· Design Review · 设计复审 (和同事审核设计文档) 60 75
· Coding Standard · 代码规范 (为目前的开发制定合适的规范) 30 20
· Design · 具体设计 75 100
· Coding · 具体编码 180 160
· Code Review · 代码复审 360 400
· Test · 测试(自我测试,修改代码,提交修改) 400 720
Reporting 报告
· Test Report · 测试报告 60 80
· Size Measurement · 计算工作量 30 30
· Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划 40 50
合计 1365 1815
原文地址:https://www.cnblogs.com/the-cat/p/7501944.html