zoukankan      html  css  js  c++  java
  • 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("
    ");
    22                             }
    23                         }
    24                     }
    25                     bw.write("
    ");
    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的原因。(心态爆炸)

    八.自我评分

  • 相关阅读:
    解决 Android SDK Manager不能下载旧版本的sdk的问题
    [置顶] 如何合并文件中的内容?
    JSTL解析——005——core标签库04
    C中的几组指针
    别动我的奶酪:CSV文件数据丢零现象及对策
    重载(overload),覆盖/重写(override),隐藏(hide)
    IOS 轻量级数据持久化 DataLite
    记录路径dp-4713-Permutation
    android 多媒体数据库详解
    Data Recovery Advisor(数据恢复顾问)
  • 原文地址:https://www.cnblogs.com/chengchenc/p/12594362.html
Copyright © 2011-2022 走看看