数独——分析、设计与测评

1、github地址:https://github.com/kinglc/sudoku1943

2、解题思路:项目包括 输入与输出(文件读写、命令行),生成不重复终局,解数独三个部分。

  (1)输入与输出

      文件读写和命令行虽然都不熟,但稍微百度就完全可以解决。

  (2)生成不重复终局

      先随便写了一个数独终局

      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

 

      3 4 5  6 7 8  9 1 2

      6 7 8  9 1 2  3 4 5

      9 1 2  3 4 5  6 7 8

      只需要生成一定数量的数独终局从简单的入手就好,上图第一行是随手写,后8行都可以看做根据第一行左移得到,第一行全排列有8!=40320种,然后交换2-3(因为数据只要求1e6,可以不 考虑),4-6,7-9行,再乘3!×3!,结果略大于1e6。

  (3)解数独

      本来试着看了一下dancing links算法,但十字链表似乎好麻烦的样子,于是老老实实用dfs暴力写完了。

3、代码设计

  (1)函数功能

    int main(int ,char *) :获取命令行参数,进入不同处理函数

    void createFinal():参数为-c时:生成终局存入数组,并调用output(int,int)函数

    void workout(int):参数为-s时:通过深搜得出终局,用check(int,int)函数判断,并调用output(int,int)函数

    bool check(int,int):判断在该处填的数字是否合理

    void output(int,int):根据参数所代表的输出顺序输出终局

    

  (2)关键函数

    生成终局:

void createFinal()
{
    int tmp[9] = { 8,9,1,2,3,4,5,6,7 };//tmp表示第一行数字
    int i, j, k, moveleft[8] = { 3,6,1,4,7,2,5,8 };    //moveleft表示2-9行在第1行基础上整体左移位数
    for (i = 0; i < 40320; i++)    //8!=40320
    {
        memcpy(numBoard[0], tmp, sizeof(tmp));
        //将第1行左移生成2-9行
        for (j = 0; j < 8; j++)
            for (k = 0; k < 9; k++)
                numBoard[j + 1][k] = numBoard[0][(k + moveleft[j]) % 9];//初始图完成
        //调换4-6,7-9行
        for (j = 0; j < 6; j++)
            for (k = 0; k < 6; k++)
            {
                output(j, k);
                if (!--testnum)
                    return;
            }
        next_permutation(tmp + 1, tmp + 9);//重置第一行
    }
    return;
}
void createFinal()

 

    解数独:

void workout(int pos)//深搜
{
    if (pos == 81)
    {
        output(0, 0);
        flag = 1;    //标记是否输出过
        return;
    }
    int i, x, y;
    x = pos / 9;
    y = pos % 9;
    if (!numBoard[x][y])
    {
        for (i = 1; i <= 9; i++)
        {
            if (cnt[i - 1] == 9)
                continue;
            numBoard[x][y] = i;//填充数字
            cnt[i - 1]++;
            if (check(pos, i))
                workout(pos + 1);
            if (flag)    //该数独已解完
                return;
            cnt[i - 1]--;
            numBoard[x][y] = 0;
        }
    }
    else
        workout(pos + 1);
}
void workout(int pos)

   (3)单元测试

 

       命令行参数判定:-c,  -s,  -abc

       运行情况判定:-c 1,  -c 1000,  -c  1000000,  -s 文件路径(其中包含1、1000、1000000个用例)

4、运行分析

    (1)生成1000个数独终局

  (2)解1000个20-40个空格的数独

  (3)优化

    在生成终局中,本来是用了三次全排列分别对第一行8个数字、第4-6行、7-9行处理,后优化为用print[6][3]={ 0,1,2,0,2,1,1,2,0,1,0,2,2,1,0,2,0,1 }存入全排列数,在output函数中处理输出。

void output(int mid,int last)
{
    int i, j, k, row;
    int order[3] = { 0 };
    order[1] = mid;
    order[2] = last;
    for (i = 0; i < 3; i++)//输出第i个三行
        for (j = 0; j < 3; j++)
        {
            row = print[order[i]][j] + 3 * i;
            for (k = 0; k < 8; k++)
                output_file << numBoard[row][k] << " ";
            output_file << numBoard[row][8]<<endl;
        }
    output_file << endl;
}
void output(int mid,int last)

5、PSP

 PSP2.1  

   Personal Software Process Stages    

 预估耗时(分钟)

 实际耗时(分钟)

Planning

计划

30

30

·Estimate

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

30

30

Development

开发

1080

 1080

·Analysis

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

120

120

·Design Spec

·生成设计文档

120

90

·Design Review

·设计复审

30

30

·Coding Standard

·代码规范

30

30

·Design

·具体设计

180

180

·Coding

·具体编码

540

540

·Code Review

·代码复审

30

30

·Test

·测试

30

60

Reporting

报告

 90

 90

·Test Report

·测试报告

40

40

·Size Measurement

·计算工作量

10

10

·Postmortem&Process Improvement Plan

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

40

40

 

合计

1200

1200

posted @ 2018-04-08 23:25  kingc  阅读(1412)  评论(0编辑  收藏  举报