软件工程实践2017第二次作业-数独生成器

github : sudoku

一. 问题描述

  • 阅读《构建之法》第一章至第三章的内容。
  • 随机生成n个不重复且已解答完毕的数独棋盘。

    数独盘面是个九宫,每一宫又分为九个小格,在每个空格上填入1-9的数字。使1-9每个数字在每一行、每一列和每一宫中都只出现一次。

  • 数独左上角第一个数为 : (学号后两位相加)%9+1。
  • 输出到sudoku.txt。

二. 问题分析与思考

  1. 数独每个格子的数字 num 的性质
    • 该行其他格子不出现 num。
    • 该列其他格子不出现 num。
    • 该宫其他格子不出现 num。

  2. 如何快速判断数字x满足上述条件可填入(r, c)格子?
    • 循环行、列、宫判断? 太慢了.
    • 牺牲部分空间,对行、列、宫已经出现的数字进行mark,便可快速判断了。

  3. 枚举数进行填充:
    • 从1到9遍历枚举. (生成的数独看着一点随机性都没有)。
    • 随机生成一个数,[1,9]之间, 以这个数为起点去枚举.(增加了数独随机性, 似乎速度上也加快了一点)。

  4. 预处理:
    • (r,c)对应的宫数 = ((r % 3) ? r : (r - 1)) / 3 * 3 + ((c % 3) ? c : (c - 1)) / 3 + 1;求优雅的计算方式。
    • (1, 1) = (学号后两位相加)%9+1。
    • 特殊输入处理。

  5. 输出优化
    • 使用putchar( )优化输出。

三. 代码设计流程图

流程图

四. 代码编写

void sudoku::dfs(int x, int y)
{
    if (flag) return;//已经输出n个则退出搜索
    int i, j;
    if (x == 9 && y == 9) {
        ++cnt;
        out();//输出数独矩阵
        if (cnt != target)  putchar('\n');
        if (cnt == target) {
            //getchar();
            flag = true;
        }
        return;
    }
    
    //填写下一格的数 
    int nx = x, ny = y + 1;
    if (ny == 10) ny = 1, ++nx;  //  跳到下一行 
    int now = getgg[nx][ny];    // 第x宫 

    //此处由循环1-9 改成 随机生成数再进行循环  => 增加数独的随机性
    int cur = rand() % 9 + 1; 
    for (i = cur; ; ) {
        // 满足该行or该列or该宫不重复
        if (!row[nx][i] && !cow[ny][i] && !gg[now][i]) {
            row[nx][i] = true, cow[ny][i] = true, gg[now][i] = true, vec[nx][ny] = i + '0';
            dfs(nx, ny);
            row[nx][i] = false, cow[ny][i] = false, gg[now][i] = false, vec[nx][ny] = '0';
        }
        ++i;
        if (i>9) i = 1;
        if (i == cur) break;
    }
    return;
}

五. 性能分析

  • 测试数据: 100w = 1e6

  • CPU使用率报告

    1505052329x2918527074.png
    • 主要耗时在于dfs.
    • let us go to dfs() ↓

  • dfs 函数分析报告

    1505052674x2918527074.png

    • 上图显示, 输出数独矩阵的函数out()与枚举数占用的比例最大.
  • 根据分析报告优化

    • 输出部分由putchar()替换printf(), 输出明显加速
    • 枚举起点采用随机数, 使得枚举的数尽可能早地满足条件
    • 还存在一定的优化问题, 有待补充.

六.输出结果

1505053309x2918527074.png

七.单元测试及代码覆盖率

有待完成...

八. PSP

PSP2.1Personal Software Process Stages预估耗时(分钟)实际耗时(分钟)
Planning计划3060
· Estimate估计这个任务需要多少时间3060
Development开发360400
· Analysis· 需求分析 (包括学习新技术)3020
· Design Spec· 生成设计文档4060
· Design Review· 设计复审 (和同事审核设计文档)3030
· Coding Standard· 代码规范 (为目前的开发制定合适的规范)3050
· Design· 具体设计6060
· Coding· 具体编码6060
· Code Review· 代码复审3020
· Test· 测试(自我测试,修改代码,提交修改)80100
Reporting报告6060
· Test Report· 测试报告2030
· Size Measurement· 计算工作量2010
· Postmortem & Process Improvement Plan· 事后总结, 并提出过程改进计划2020
合计450520

九. 补充

  1. 关于putchar比printf快? 2017.9.14
    • putchar, 单字符输出,无格式控制, 速度快
    • printf 格式化输出, 比putchar慢.

转载于:https://www.cnblogs.com/winforbest/p/7500564.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值