• 软件工程实践2019秋第三次作业


    第一次个人编程作业

    Github仓库地址https://github.com/JoekrLSJ/031702444

    1.PSP表格

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

    2.解题过程

    (1)解题思路

    ​ 读完题目,第一个想法就是DFS+回溯,总结了一下宫格的特征,发现可以分成两类,一类是有宫的(四六八九宫格),一类是无宫的,即只要判断行列是否冲突(三五七宫格)。题目说是唯一解,所以每次只要填入的是没有冲突的数字,最后能全部填完,就是答案。

    (2)程序设计流程图

    (3)代码实现

    Soduku.cpp 1.0

    要点说明

    这是最初的版本,先从简单的三五七宫格入手,只要设置行列标记,位置不冲突即可填入,填不完回溯,最后填完就是答案。
    设置标记

    int  Soduku_map_row[maxn][maxn];								//行标记,未填入为0
    int  Soduku_map_column[maxn][maxn];								//列标记,未填入为0
    int  flag;														//填完标记
    

    用结构体队列存储待填格子行列位置

    struct node
    {
    	int nrow;
    	int ncolumn;
    } blank_node[maxn*maxn],pos_node[maxn];                         //记录未填入宫格的行列坐标
    
    

    求解方法:DFS+回溯函数

    Soduku_find()

    调用这个函数计算三五七宫格数独

    
    void Soduku_find(int now)
    {
    	if (flag) return;
    	if (now == blank_node_count + 1)
    	{
    		flag = 1;
    		return;
    	}
    	int x = blank_node[now].nrow;
    	int y = blank_node[now].ncolumn;
    	rep(i, 1, n)
    	{
    		if ((!Soduku_map_row[x][i]) && (!Soduku_map_column[y][i]))
    		{
    			Soduku_map_row[x][i] = 1;					//行不冲突
    			Soduku_map_column[y][i] = 1;				//列不冲突
    			Soduku_map[x][y] = i;						//这个格子填入i
    			Soduku_find1(now + 1);						//填下一个格子
    			if (flag) return;                           //填完退出
    			Soduku_map_row[x][i] = 0;					//行标记
    			Soduku_map_column[y][i] = 0;				//列标记
    		}
    	}
    }
    
    

    输入函数 Soduku_input()

    void Soduku_input()
    {
    	rep(i, 1, n)
    	{
    		rep(j, 1, n)
    		{
    			cin >> Soduku_map[i][j];
    			if (Soduku_map[i][j] == 0)
    			{
    				blank_node_count++;
    				blank_node[blank_node_count].nrow = i;
    				blank_node[blank_node_count].ncolumn = j;
    			}
    			else
    			{
    				Soduku_map_row[i][Soduku_map[i][j]] = 1;
    				Soduku_map_column[j][Soduku_map[i][j]] = 1;
    				if (!(n == 3 || n == 5 || n == 7))
    				{
    					int pos = getpostion(i, j, pos_node[n].nrow, pos_node[n].ncolumn, n);
    					Soduku_positon[pos][Soduku_map[i][j]] = 1;
    				}
    			}
    		}
    	}
    }
    
    

    输出函数 Soduku_outputput()

    void Soduku_output()
    {
    	rep(i, 1, n)
    	{
    		rep(j, 1, n)
    		{
    			if (j != n)cout << Soduku_map[i][j] << " ";
    			else cout << Soduku_map[i][j];
    		}
    		cout << endl;
    	}
    	cout << endl;
    }
    
    

    Soduku.cpp 2.0

    由于四六八九宫格每种宫格的行列划分的方法不一样,所以设计了一个函数输入待填位置的行列坐标和小宫格行列数以及大宫格的边长就能算出当前位置在哪个宫格。

    宫格函数int getpostion(int,int,int,int,int)

    
    int getpostion(int x, int y, int row, int column, int n)
    {
    	return (x - 1) / row * (n / column) + (y - 1) / column + 1;
    }
    

    举个例子,在九宫格(5,4)位于第5宫格,(5 - 1)/ 3 *(9 / 3)+ (4 -1)/ 3 +1=5。每个宫格3行3列,(x - 1)/ row算出在第几行的宫格,乘上每行有(n / cloumn)个宫格,再加上在第几列的宫格上(y - 1) / column + 1,最后就是所在宫格的位置。

    加入宫标记

    Soduku_positon[maxn][maxn];									//宫标记,未填入为0
    

    增加void Soduku_find2(int)函数,计算四六八九宫格数独。

    
    void Soduku_find2(int now)
    {
    	if (flag) return;
    	if (now == blank_node_count + 1)
    	{
    		flag = 1;
    		return;
    	}
    	int x = blank_node[now].nrow;
    	int y = blank_node[now].ncolumn;
    	int pos = getpostion(x, y, pos_node[n].nrow, pos_node[n].ncolumn, n);
    	rep(i, 1, n)
    	{
    		if ((!Soduku_map_row[x][i]) && (!Soduku_map_column[y][i]) && (!Soduku_positon[pos][i]))
    		{
    			Soduku_map_row[x][i] = 1;					//行不冲突
    			Soduku_map_column[y][i] = 1;				//列不冲突
    			Soduku_positon[pos][i] = 1;					//宫不冲突
    			Soduku_map[x][y] = i;						//这个格子填入i
    			Soduku_find2(now + 1);						//填下一个格子
    			if (flag) return;                           //填完退出
    			Soduku_map_row[x][i] = 0;					//行标记
    			Soduku_map_column[y][i] = 0;				//列标记
    			Soduku_positon[pos][i] = 0;					//宫标记
    		}
    	}
    }
    
    

    (4)单元测试样例

    三宫格

    四宫格

    五宫格

    六宫格

    七宫格

    八宫格

    九宫格

    后面简单写了个批处理文件test.bat测试一下输出结果的正确性。

    test.bat代码

    
    @echo off
    title "Black Box Test"
    for %%i in (3,4,5,6,7,8) do
     (
    echo 当前测试第m%%in5组:
    echo 5 %%i > input.txt
    type m%%in5.txt >> input.txt
    Sudoku
    fc output.txt m%%in5_answer.txt /W
    pause >nul
    del input.txt
    del output.txt
    )
    
    

    如果输入文件output.txt和m3n5answer.txt内容一致答案正确就会显示“找不到相异处”,反之会提示两个文件不一样的地方。

    (5)异常处理

    在编译的时候一直出现C4996的错误无法消除,查了一下是因为freopen和预处理器的问题,通过在预处理器最上方,也就是第一行添加如下代码,即可解决该错误:

    
    #pragma warning(disable:4996)
    
    

    (6)性能分析

    3.回顾总结

    ​这次题目难度不是很难,主要的时间都花在了熟悉VS 2017的使用,学习如何创建项目,初步学习使用性能分析工具,现在还不是很熟练,后面要熟练掌握。这次还学习了PSP流程,顺便复习了一下int main(int argc,int *argv[])的使用方法。最后熟悉了在Github上面管理代码的方法和流程。

  • 相关阅读:
    TCP 登录实现代码
    网络编程步骤 乔老师整理
    网络编程步骤 乔老师整理
    UDP 编程 客服咨询回复
    UDP 编程 客服咨询回复
    利用java在服务器和客服端建立连接,进行通讯(代码实例)
    利用java在服务器和客服端建立连接,进行通讯(代码实例)
    InetAddress 类简介
    InetAddress 类简介
    Mysql并发时经典常见的死锁原因及解决方法
  • 原文地址:https://www.cnblogs.com/JokerLSJ/p/11586555.html
Copyright © 2020-2023  润新知