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


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

    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
  • 相关阅读:
    mac下的docker的Docker.raw占用空间很大?
    python模块uuid产生唯一id
    缓存溢出Buffer Overflow
    (原创)攻击方式学习之(3)
    JSP禁用缓存的方式 response.setHeader( "Pragma", "no-cache" ); setDateHeader("Expires", 0);
    Java框架安全
    Java Web:主动和被动方式检测安全的框架
    一.配置简单的嵌入式tomcat和jetty
    使用embeded tomcat进行嵌入式javaee开发-启动tomcat
    安全隐患,你对X-XSS-Protection头部字段理解可能有误
  • 原文地址:https://www.cnblogs.com/xiezhe1204/p/7634938.html
Copyright © 2020-2023  润新知