2020软件工程作业03

软件工程
https://edu.cnblogs.com/campus/zswxy/software-engineering-2017-1
作业要求
https://edu.cnblogs.com/campus/zswxy/software-engineering-2017-1/homework/10494
作业目标
给出PSP表格、描述解题思路、设计实现过程、改进程序性能、展示关键代码、撰写心路历程与收获。
作业正文  如下
参考文献
百度、CSDN、问同学

1、Github项目地址

 https://github.com/Risiblejdd/work/tree/master/src

2、PSP表格

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



3、解题思路

百度百科简介:
数独盘面是个九宫,每一宫又分为九个小格。在这八十一格中给出一定的已知数字和解题条件,利用逻辑和推理,在其他的空格上填入1-9的数字。使1-9每个数字在每一行、每一列和每一宫中都只出现一次,所以又称“九宫格”。

这个题目首先想到的就是深搜+回溯的算法。但是对于编程,对于算法,我真的是只会说不会做。所以一看到这次作业我就头疼,但是还是要迎难而上啊啊啊啊啊(哭哭/(ㄒoㄒ)/~~!!!

首先开始阶段,要先初始化数独盘,在题目已经填写的数字基础上对我们要填的格子进行填充限制,如下图所示:

然后是数字填充阶段,回溯法,就是在已有的限制条件下,按顺序尝试1-9在格子中的填充,如果在尝试过程中填写到了数独盘的最后一格,则代表数独已经解出来了(此方法仅限提供的数独盘只有唯一解,如果有多解也只能输出一个),如果到达某格无法继续填充后续数字,需要移除之前放置的数字,然后继续尝试,如下图所示:


4、实现过程

3、4、5、6、7、8、9阶测试






5、改进程序性能







6、关键代码

回溯方法:

/**
	 * 回溯填充方法
	 * @param row
	 * @param col
	 */
	public void backtrack(int row, int col) {
			
		
		if(shudoPan[row][col] == 0) {
			for(int d = 1; d <= m; d++) {
				int idx = 0;
				if(boxRow > 0) {
					idx = (row / boxRow ) * boxRow + col / boxCol;
				}
				
				if(couldPlace(d, row, col)) {
					//填充数字,并设置填充限制
					boxOccupied[idx][d]++;
					rowOccupied[row][d]++;
				    colOccupied[col][d]++;
				    shudoPan[row][col] = d;
				    //是否填充到最后一格
					if ((col == m-1) && (row == m-1)) {
					      sudokuSolved = true;
					    }
					    else {
					      //当到达最后一列的格子,下一个格子跳转到下一行
					      if (col == m-1) {
					    	  backtrack(row + 1, 0);
					      }else {
					    	  backtrack(row, col + 1);
					      } 
					    }
					if(!sudokuSolved) {//移除填充后无法进行后续填充的数
						
						boxOccupied[idx][d]--;
						rowOccupied[row][d]--;
						colOccupied[col][d]--;
						shudoPan[row][col] = 0;
					}
				}
			}
		}else {
			if ((col == m-1) && (row == m-1)) {
			      sudokuSolved = true;
			    }
			    else {
			      //当到达最后一列的格子,下一个格子跳转到下一行
			      if (col == m-1) {
			    	  backtrack(row + 1, 0);
			      }else {
			    	  backtrack(row, col + 1);
			      } 
			    }
		}
	}

解数独方法---用于初始化和调用回溯方法。

代码中的idx = (i / boxRow ) * boxRow + k / boxCol;是根据m宫格的宫格行列大小boxROW、boxCol来确定待解格子所在宫号(假设宫按顺序从左到右,自上而下标号为0~(idx-1))。

/**
	 * 解数独方法
	 */
	public void solveSudoku(int[][] shudoPan) {
		setBox();//调用设置宫的行列数方法
		//System.out.println("boxRow,boxCol:"+boxRow+" "+boxCol);
		
	    // 初始化某数所在行、列、宫
	    for (int i = 0; i < m; i++) {
	      for (int k = 0; k < m; k++) {
	        int num = shudoPan[i][k];
	        if (num != 0) {
	          int d = num;
	          if(boxRow > 0) {
	        	  int idx = (i / boxRow ) * boxRow + k / boxCol;
	        	  boxOccupied[idx][d]++;
	          }
	          rowOccupied[i][d]++;
	          colOccupied[k][d]++;
	        }
	      }
	    }
	    backtrack(0, 0);
	  }
}

设定宫的大小.

如果宫格阶数为3、5、7的话就把代表宫格行列大小的boxRow、boxCol设为-1,用于后面判断使用。这样的好处是实现了对原来9宫格功能的扩展。

/**
	 * 设定宫的大小
	 */
	public static void setBox() {
		if(m == 4) {
			boxRow = 2;
			boxCol = 2;
		}
		if(m == 6) {
			boxRow = 2;
			boxCol = 3;
		}
		if(m == 8) {
			boxRow = 4;
			boxCol = 2;
		}
		if(m == 9) {
			boxRow = 3;
			boxCol = 3;
		}
		if(m == 3 || m == 5 || m == 7) {
			boxRow = -1;
		}
	}

对文件中读取到的数据,取得其中第numb个数独盘并进行解数独。

其中包含三行
Initialize(rowOccupied);
Initialize(colOccupied);
Initialize(boxOccupied);
是个循环初始化占位数组方法Initialize,用于计算完一个数独盘后将用来标记占位的三个数组重新归0;

/**
	 * 取得第numb个数独盘并进行解数独
	 * @param numb
	 * @param m
	 */
	public void getAndDO(int numb) {
		int index;
		for(int i = 0; i < m; i++) {
			index = numb*m+i;
			Slipt(hang.get(index));
		}
		//将三个判断占位的数组初始化为0,把判断数独是否解完初始化为false
		Initialize(rowOccupied);
		Initialize(colOccupied);
		Initialize(boxOccupied);
		sudokuSolved = false;
		solveSudoku(shudoPan);
		j = 0;
	}

7、心路历程与收获

   写到这里我实在是头昏眼花了,为了此次作业,这两周除了上课我每天从早到晚都坐在电脑前,各种百度查资料,然后还是很多借鉴了别人的,才勉强提交了作业。从什么时候开始我感觉自己不适合编程呢,大概是从大二的时候。入学以来,无论上什么课我都十分积极认真,所以我的成绩也一直是班级第一。也许其他同学会觉得我厉害,但只有我自己知道我的优势只在数学,只在理论,只在想法。大一有好几门和数学相关的学科,对数学极其敏感的我轻而易举地就取得了班级第一。然后大二我们开始更多地上专业课,我上课还是那么认真,课后也会去自学。因为很喜欢李津老师教的Java,我决定把Java当作自己擅长的语言,我不仅用Java完成作业,也在洛谷和pta上疯狂刷题。当然我是有进步的,但是很快我就遇到了新的问题,那就是算法。无论用什么样的语言,算法是避免不了的。由于我对数学的敏感,其实很多时候我总是很快就能想到解决问题的方法,但是让我去用编程实现,我就像是瞬间丧失了自己所会的一切。明明大家都说,想要编程好数学一定要好,可是我感觉自己数学还算不错,但编程真的没法说。之前的数据结构、操作系统、算法分析,每次有那种团队实验作业,我的想法都是最快出来的的那个,但编程能力去真的差到不行。我不敢说我上课是最认真的那个,但是我一定是上所有课都认真的那个,给我们上过课的老师们都知道。我也有课后去各种网站自学钻研,各种刷题。可我一直找不到提升自己编程能力的方法,然后这次的作业让我更加困惑于此。说这么多,我只是想表明我真的在努力去做好。两周的时间,让我收获了什么呢?让我更看清了自己的优势劣势,让我更清楚了自己的坐标,我在想是不是要重新定位一下自己的目标。我还是先去做一下其他科目的作业⑧,为了这个囤了好多其他作业QAQ。

8、评分

原文地址:https://www.cnblogs.com/risiblejdd/p/12591807.html