sudoku

1.GitHub地址:https://github.com/Fionayxy/sudoku

2.

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

3.解题思路

看到题目后毫无头绪,尤其是对命令行、GitHub等毫无了解而且对C++了解甚少,C#完全不会,因此一拖再拖。

后来在查询了main函数的参数意义,如何使用C++创建或打开本地文件、编辑文件,并在同学的帮助下,学会了github的皮毛。

(1)生成数独

刚开始百度如何生成数独,研究网上的代码和思路,进展十分缓慢。最后同学给我讲解了他的思路,即:

先定义第一行数字(学号尾号37,(3+7)%9+1=2)

int tmp[9] = { 2,3,4,5,6,7,8,9,1 };

之后8行的数字排列可看做是对第一行数字进行移动

 因为九宫格中的数字不能重复,因此将2-8行右移相应格数

int moveright[8] = { 3,6,1,4,7,2,5,8 };

由于第一行第一个数应保持为2不变,对其余8个数进行全排列,一共有8!=40320种

且在每一个情况下,都可变换4-6行、7-9行的位置,即每个确定的第一行都有3!×3!=36种不同的终局

因此最终可生成终局40320×36=1451520(种)>1e6(种)

全排列时用到了 <algorithm>头文件下的函数

bool next_permutation(iterator start,iterator end)

(2)解数独

采用了递归的方法,从第一个格子开始

对每个格子,如果该格已有有效数(1-9),则遍历下一格,若没有有效数,则从1-9寻找满足条件(行、列、九宫格无重复数字)的所有侯选数

遍历直至最后一个格子,输出当前数独

由于本题只要求输出一个可行解,因此在首次输出后,直接结束即可。

4.设计实现过程

int main(int argc, char *argv[])

void Sudoku(int a[9][9], int n)   //数独求解函数

bool check(int a[9][9], int i, int j, int k)//判断是否可以将第i行、第j列的数设为k

void print(int a[9][9])//输出可行的解

int convert(char* str)//判断输入的字符串是否均为数字(即n)

void creat_shudu() //生成终局并输出到sudoku文件中

5.性能分析

生成500个数独终局

 

解数独测试用例

0 8 0 0 0 1 6 0 0
0 7 0 4 0 0 0 2 1
5 0 0 3 9 6 0 0 0
2 0 4 0 5 0 1 3 0
0 0 8 9 0 7 5 0 0
0 5 7 0 3 0 9 0 0
0 0 0 5 6 3 0 0 9
3 1 0 0 0 2 0 5 0
0 0 5 8 0 0 0 4 0

0 1 2 6 8 0 0 9 0
6 0 0 0 0 4 0 1 0
8 0 5 2 0 0 3 7 0
0 0 0 0 0 7 5 2 3
0 0 0 4 0 6 0 0 0
3 8 1 9 0 0 0 0 0
0 5 4 0 0 2 8 0 1
0 7 0 3 0 0 0 0 2
0 3 0 0 5 9 7 6 0

0 4 7 0 5 0 0 0 8
6 0 5 0 3 0 2 0 1
0 0 0 7 0 6 0 3 0
0 0 6 0 7 0 0 2 4
9 0 0 8 0 4 0 0 6
4 5 0 0 1 0 9 0 0
0 1 0 5 0 2 0 0 0
2 0 8 0 4 0 5 0 3
5 0 0 0 9 0 7 1 0

0 0 9 0 0 1 6 2 0
5 7 0 0 2 8 0 3 0
3 0 0 7 0 0 0 0 4
8 9 0 0 7 0 4 0 0
0 6 0 5 0 3 0 9 0
0 0 1 0 9 0 0 7 6
6 0 0 0 0 7 0 0 8
0 4 0 1 3 0 0 6 5
0 2 7 6 0 0 9 0 0

6.代码说明

(1)解数独

void Sudoku(int a[9][9], int n) {
    int temp[9][9];
    int i, j;
    for (i = 0; i<9; i++) {
        for (j = 0; j<9; j++)
            temp[i][j] = a[i][j];
    }
    i = n / 9;
    j = n % 9; //求出第n个数的行数和列数
    if (a[i][j] != 0) { //已经有原始数据
        if (n == 80) {  //是最后一个格子,输出可行解
            print(temp);
        }
        else    //不是最后一个格子,求下一个格子
            Sudoku(temp, n + 1);
    }
    else { //没有数据
        for (int k = 1; k <= 9; k++) {
            bool flag = check(temp, i, j, k);
            if (flag) { //第i行、第j列可以是k
                temp[i][j] = k; //设为k
                if (n == 80) {
                    print(temp);
                    break;
                }
                else
                    Sudoku(temp, n + 1);
                temp[i][j] = 0; //恢复为0,判断下一个k
            }
        }
    }
}

(2)生成终局

void creat_shudu() //生成终局并输出到sudoku文件中
{
    int tmp[9] = { 2,3,4,5,6,7,8,9,1 };//tmp表示第一行数字
    int i, j, k, moveright[8] = { 3,6,1,4,7,2,5,8 };    //右移位数
    for (i = 0; i < 40320; i++)    //8!=40320
    {
        memcpy(map[0], tmp, sizeof(tmp));
        for (j = 0; j < 8; j++)
            for (k = 0; k < 9; k++)
                map[j + 1][(k + moveright[j]) % 9] = map[0][k];//初始模板
        int row[9] = { 0,1,2,3,4,5,6,7,8 };//fol函数是接下来输出的1-9行对应数独模板的fol行
        for (j = 0; j < 6; j++)
        {
            if (j != 0)
                next_permutation(row + 3, row + 6);//此函数是求4-7行的下一个排列
            for (k = 0; k < 6; k++)
            {
                if (k != 0)
                    next_permutation(row + 6, row + 9);
                for (int a = 0; a < 9; a++)
                {
                    for (int b = 0; b < 9; b++)
                    {
                        if (b == 0)
                            output << map[row[a]][b];
                        else
                            output << " " << map[row[a]][b];
                    }
                    output << endl;
                }
                output << endl;
                if (!--n)
                    return;
            }//完成一次数独的输出
            row[6] = 7, row[7] = 8, row[8] = 9;
        }//每种数独模板有36种形式,最多能输出8!*36=1451520种
        next_permutation(tmp + 1, tmp + 9);//对tmp函数进行一次全排列
    }
    return;
}
原文地址:https://www.cnblogs.com/y-x-y/p/8886415.html