2020软件工程作业03

软件工程 [https://edu.cnblogs.com/campus/zswxy/software-engineering-2017-1]
作业要求 [https://edu.cnblogs.com/campus/zswxy/software-engineering-2017-1/homework/10494]
作业目标 编程解数独
作业正文  https://www.cnblogs.com/chengchenc/p/12594362.html
其他参考文献 CSDN

       Github项目地址:https://github.com/chengchen-a/sofeware-student/tree/master

PSP2.1Personal 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     }
setBox

 

(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     }
IO Code

(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     }
Backtrack

(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 }
solveSUoku

 

五.测试(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的原因。(心态爆炸)

 

 

八.自我评分

 

posted @ 2020-03-29 19:56  chencheng1024  阅读(252)  评论(0编辑  收藏  举报