2020软件工程作业03
Github项目地址:https://github.com/chengchen-a/sofeware-student/tree/master
PSP2.1 | Personal Software Process Stage | 预估耗时(f分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 60 | 85 |
Estimate | 估计这个任务需要多少时间 | 4818 | 6475 |
Development | 开发 | 120 | 450 |
Analysis | 需求分析(包括学习新技术) | 65 | 165 |
Design Spec | 生成设计文档 | 160 | 185 |
Design Review | 设计复审(和同事审核设计文档) | 30 | 65 |
Coding Standard | 代码规范(为目前的开发制定合适的规范) | 50 | 170 |
Design | 具体设计 | 180 | 250 |
Coding | 具体编码 | 3600 | 4010 |
Code Review | 代码复审 | 195 | 250 |
Test | 测试(自我测试,修改代码,提交修改) | 158 | 340 |
Reporting | 报告 | 65 | 125 |
Test Report | 测试报告 | 45 | 150 |
Size Measurement | 计算工程量 | 30 | 45 |
Postmortem & Process Improvement Plan | 事后总结提出过程改进计划 | 60 | 185 |
合计 | 4818 |
6475 |
一.解题思路
看到这个问题,我就觉得头有点蒙,数独小时候有过接触,但至今也没有破解过一个数独。首先想到的是数独的规则,1~9不重复填满9X9的盘面,我首先想到的是蛮力法,但考虑到蛮力法的代价太大,便放弃。又想到这个数独问题和八皇后问题有点类似,又去论坛查了些资料,发现回溯法的确是解数独的一个好算法。但算法对我来说一直是个头疼的问题,所以需要复习一下回溯法
1.了解规则
PS: 数独规则
对于一个数独问题,我们需要在9*9的空格内填入数字。这9*9被分成9个3*3的小块N1 - N9,要 保证每个小块Ni包含的数字必须是1至9,不能重复。同时,9*9的矩阵每一行和每一列都不能 用 重复 数字。
2.阶段化
直接从九宫格开始,只要实现了对9盘面的破解,自然而然就能破解3盘面
(1)初始化阶段
如果某个数字在盘面以存在,则设置为true,在同行同列同块中填数时需要排除为true的数字
(2)填数阶段
回溯填充,除去已为true的数字后从1~9按序填充,如果填充到最后一格,则破解成功,如果 中途无法填充,则移除已填充的数字,再从新填充,直到破解成功。
3.调用方法详解
4.具体方法代码
(1)盘面设置方法:设置盘面大小

1 public static void setBox() { 2 if(m == 4) { 3 boxRow = 2; 4 boxCol = 2; 5 } 6 if(m == 6) { 7 boxRow = 2; 8 boxCol = 3; 9 } 10 if(m == 8) { 11 boxRow = 4; 12 boxCol = 2; 13 } 14 if(m == 9) { 15 boxRow = 3; 16 boxCol = 3; 17 } 18 if(m == 3 || m == 5 || m == 7) { 19 boxRow = -1; 20 } 21 }
(2.)文件IO方法:读写TXT文件数据

1 /** 2 * 写入文件 3 */ 4 public void writeFile(boolean isDone){ 5 try { 6 FileWriter bw = null; 7 File newFile = new File(outputPath); 8 if(!newFile.exists()) { 9 newFile.createNewFile(); 10 } 11 if(isDone == true) { 12 bw = new FileWriter(newFile,isDone); 13 { 14 for(int i = 0;i < m; i++) { 15 for(int k = 0; k < m; k++) { 16 if(k != m-1) { 17 bw.write(String.valueOf(shudoPan[i][k])); 18 bw.write(" "); 19 }else { 20 bw.write(String.valueOf(shudoPan[i][k])); 21 bw.write("\n"); 22 } 23 } 24 } 25 bw.write("\n"); 26 bw.flush(); 27 bw.close(); 28 } 29 }else { 30 bw = new FileWriter(newFile,isDone); 31 bw.write(""); 32 } 33 34 }catch(IOException e) { 35 e.printStackTrace(); 36 } 37 }
(3)回溯方法:回溯填充盘面

1 public void backtrack(int row, int col) { 2 3 4 if(shudoPan[row][col] == 0) { 5 for(int d = 1; d <= m; d++) { 6 int idx = 0; 7 if(boxRow > 0) { 8 idx = (row / boxRow ) * boxRow + col / boxCol; 9 } 10 11 if(couldPlace(d, row, col)) { 12 //向盘面中填充数字,并设置填充限制 13 boxOccupied[idx][d]++; 14 rowOccupied[row][d]++; 15 colOccupied[col][d]++; 16 shudoPan[row][col] = d; 17 //检查是否填充到最后一格 18 if ((col == m-1) && (row == m-1)) { 19 sudokuSolved = true; 20 } 21 else { 22 //填充完列后跳转到下一行继续填充 23 if (col == m-1) { 24 backtrack(row + 1, 0); 25 }else { 26 backtrack(row, col + 1); 27 } 28 } 29 if(!sudokuSolved) { 30 //移除已填充的数 31 boxOccupied[idx][d]--; 32 rowOccupied[row][d]--; 33 colOccupied[col][d]--; 34 shudoPan[row][col] = 0; 35 } 36 } 37 } 38 }else { 39 if ((col == m-1) && (row == m-1)) { 40 sudokuSolved = true; 41 } 42 else { 43 //当到达最后一列的格子,下一个格子跳转到下一行 44 if (col == m-1) { 45 backtrack(row + 1, 0); 46 }else { 47 backtrack(row, col + 1); 48 } 49 } 50 } 51 }
(4)数独破解方法:初始化盘面及调用回溯方法

1 public void solveSudoku(int[][] shudoPan) { 2 setBox();//调用设置宫的行列数方法 3 //System.out.println("boxRow,boxCol:"+boxRow+" "+boxCol); 4 5 // 初始化某数所在行、列、宫 6 for (int i = 0; i < m; i++) { 7 for (int k = 0; k < m; k++) { 8 int num = shudoPan[i][k]; 9 if (num != 0) { 10 int d = num; 11 if(boxRow > 0) { 12 int idx = (i / boxRow ) * boxRow + k / boxCol; 13 boxOccupied[idx][d]++; 14 } 15 rowOccupied[i][d]++; 16 colOccupied[k][d]++; 17 } 18 } 19 } 20 backtrack(0, 0); 21 } 22 }
五.测试(Ecilpse+IDEA+Terminal )
ps:与input相同的output数据是无法破解的额数独
六.性能测试
PS:测试环境(jprofiler10+IDEA2019+Jdk10.0.2)
PS:我也不知道为什么会这样子,
七.遇到的问题
(1)IDEA中TERMINAl的问题
①字符集的设置
在idea中打开cmd对java类进行编译时idea的字符集和cmd的字符集不同是会报(0xA8)错误
解决方法:在javac后加入语句“-encoding UTF-8 ”
②:idea找不到符号的问题,代码本身没有问题,似乎是idea插件的问题,
解决方法:暂时无法解决,不过可以直接在的idea外运行编译java类来直接避开这个问题,这也是我使用了IDEA还要用Ecilpse的原因。(心态爆炸)
八.自我评分
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步