• 数独


    ---恢复内容开始---

    一、Github地址: https://github.com/xiaxiaxiaxiajie/sudoku1962

    二、PSP

    PSP2.1  

    Personal Software Process Stages    

    预估耗时

    (分钟)

    实际耗时

    (分钟)

    Planning

    计划

    40

    35

    ·Estimate

    ·估计这个任务需要多少时间

    20

    20

    Development

    开发

    1100

    1200

    ·Analysis

    ·需求分析(包括学习新技术)

    180

    210

    ·Design Spec

    ·生成设计文档

    120

    150

    ·Design Review

    ·设计复审

    30

    20

    ·Coding Standard

    ·代码规范

    30

    30

    ·Design

    ·具体设计

    240

    270

    ·Coding

    ·具体编码

    1200

    1000

    ·Code Review

    ·代码复审

    120

    300

    ·Test

    ·测试

    60

    120

    Reporting

    报告

    120

    120

    ·Test Report

    ·测试报告

    30

    20

    ·Size Measurement

    ·计算工作量

    10

    10

    ·Postmortem&Process Improvement Plan

    ·事后总结并提出过程改进计划

    80

    80

     

    合计

    3260

    3585

    三、解题思路:

      拿到题目看到要求时,有些词不知道是什么,感觉很麻烦,因此有不想做的心理(就是懒,真不好),开始着手分析题目后,首先要下手的就是代码部分,代码根据题目要求一共有两块,一块是解数独部分,一块是生成数独部分。

    1. 解数独:

      用dfs从第一排开始到最后一排,依次找到空格,从数字1到9循环,判断是否能填该数字(即当前数字所处横排、竖排、九宫格是否有该数字出现过),可以填,接着往下的dfs,不可以换数字,如果没有可填的数字,返回上一次。

    2.生成数独终局

      例如一个简单的数独以9为第一个数字(学号62:6+2+1=9)

      9  1  2    3  4  5    6  7  8

      3  4  5    6  7  8    9  1  2

      6  7  8    9  1  2    3  4  5

      1  2  3    4  5  6    7  8  9

      4  5  6    7  8  9    1  2  3

      7  8  9    1  2  3    4  5  6

      2  3  4    5  6  7    8  9  1

      5  6  7    8  9  1    2  3  4

      8  9  1    2  3  4    5  6  7

      除了第一排第一个数之外,第一排的任意数的位置均可改变,个数为 8! = 40320 种,4、5 、6行可互换位置,7、8、9行可互换位置,即有 8! *  3!* 3! > 1e6  种。

    四、代码设计

    int main(int argc, char *argv[])  //主函数, 获取命令参数
    
    bool judge(char *s)//判断输入的数是否有效
    
    void creat_sudoku()//生成数独终局函数
    
    void get_init()//在解数独中对应给定的数独对三个状态数组进行初始化
    
    void dfs(int x, int y)//解数独函数,用dfs深度优先搜索
    
    bool judge_shudu(int x, int y, int n)//判断x行y列这个位置是否可以放置数字n
    
    void output()//打印函数,将数独输出到指定的txt文件中

    五、关键代码展示

    1. 生成终局

    void creat_sudoku()//生成数独终局函数
    {
        m = 0;//记录当前生成多少个数独,n是要生成的数独数
        int tmp[10] = { 0,9,1,2,3,4,5,6,7,8 };//tmp 1-9是第一行要生成的数
        int moveleft[10] = { 0,0,3,6,1,4,7,2,5,8 };    //moveleft表示2-9行在第1行基础上整体左移位数
        for (int i = 1; i <= 40320; i++)    //8!=40320
        {
            for (int j = 1; j <= 9; j++)
                shudu[1][j] = tmp[j];
    
            for (int j = 2; j <= 9; j++)
            {
                for (int k = 1; k <= 9; k++)
                {
                    int pos = k - moveleft[j];
                    if (pos <= 0) pos += 9;
                    shudu[j][k] = shudu[1][pos];
                }
            }//生成一个数独模板
    
            int fol[10] = { 0,1,2,3,4,5,6,7,8,9 };//fol函数是接下来输出的1-9行对应数独模板的fol行
            for (int j = 1; j <= 6; j++)
            {
                if (j != 1)next_permutation(fol + 4, fol + 7);//此函数是求4-7行的下一个排列
                for (int k = 1; k <= 6; k++)
                {
                    if (k != 1)next_permutation(fol + 7, fol + 10);
                    for (int p = 1; p <= 9; p++)
                    {
                        for (int q = 1; q <= 9; q++)
                        {
                            if (q == 1)Output << shudu[fol[p]][q];
                            else Output << " " << shudu[fol[p]][q];
                        }
                        Output << endl;
                    }
                    Output << endl;
                    if (++m >= n)
                        return;
                }//完成一次数独的输出
                fol[7] = 7, fol[8] = 8, fol[9] = 9;
            }//每种数独模板可以输出36种子数独,所以最多能输出8!*36=1451520种
            next_permutation(tmp + 2, tmp + 10);//对tmp函数进行一次全排列
        }
        return;
    }

    2. 解数独

    void dfs(int x, int y)//解数独函数,用dfs深度优先搜索
    {
        if (flag) return;
        if (y > 9) {
            x++; y = 1;
        }
        if (x == 10 && flag == 0) {
            output();
            flag = 1;
            return;
        }//此时每一位都放置了数字,则输出
    
        if (!shudu[x][y])
        {
            for (int i = 1; i <= 9 && !flag; i++)
            {
                if (judge_shudu(x, y, i))
                {
                    line[x][i] = 1;
                    orl[y][i] = 1;
                    block[getblocknum(x, y)][i] = 1;
                    shudu[x][y] = i;
                    dfs(x, y + 1);
                    line[x][i] = 0;
                    orl[y][i] = 0;
                    block[getblocknum(x, y)][i] = 0;
                    shudu[x][y] = 0;
                }
            }
        }
        else dfs(x, y + 1);
    }//判断x行y列要放置1-9中的哪一位数字,递归实现

    3. 单元测试  

      命令行参数测试: -c  -s  -1  -a

      运行情况:-c 1  -c 1000   -c 100000   -s 文件路径 

    六、性能分析

    1. 生成1000个数独终局

      

    2. 生成1e6个数独

    3. 解1个数独

     

    4. 解10个数独

    5. 解1000个数独

    ---恢复内容结束---

  • 相关阅读:
    ZABBIX自动发现添加主机功能
    Kafka史上最详细原理总结
    python的基本函数
    windows和linux出现timewait过多的解决方法
    Ext.Net使用DirectMethod.request调用一般处理程序(.ashx)并传递参数
    $.post、$.get、$.ajax三者的区别
    .net Web应用程序添加WebService引用时报错的问题
    ASP.NET TreeView控件各个节点总是居中对齐,而不是左对齐的问题
    利用Win8上的IIS来部署ASP网站
    做文件目录DEMO时发现的问题
  • 原文地址:https://www.cnblogs.com/-jie/p/8847646.html
Copyright © 2020-2023  润新知