zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    requets中urlencode的问题
    洛谷$P4503 [CTSC2014]$企鹅$QQ$ 哈希
    洛谷$P5446 [THUPC2018]$绿绿和串串 $manacher$
    洛谷$P5329 [SNOI2019]$字符串 字符串
    洛谷$P1390$ 公约数的和 欧拉函数
    洛谷$P4318$ 完全平方数 容斥+二分
    入门懵逼钨丝繁衍
    $ CometOJ-Contest#11 D$ $Kruscal$重构树
    洛谷$P4884$ 多少个1? 数论
    入门数论简单总结
  • 原文地址:https://www.cnblogs.com/the-cat/p/7501944.html
Copyright © 2011-2022 走看看