软件工程实践 2017 第二次做业(部分)

相关连接

做业题目地址:软件工程实践 2017 第二次做业
课程博客目录:软工课程做业博客目录-031502627
项目 GitHub 地址:egbertwang / Sudokuhtml

估计耗时

项目 more

题目概述

数独要点

每一行、每一列、每个粗线宫(3*3)内的数字均含1-9,不重复。java

工具清单

  • 编程语言:C/C++
  • 编程工具:Code::Blocks
  • 效能分析工具:
  • 源代码管理平台:Github
  • 博客编辑器:Atom

要求

输入

n //数独棋盘个数git

输出

随机生成N个不重复的已解答完毕的数独棋盘,并输出到sudoku.txt中,而且左上角的第一个数为:(学号后两位相加)% 9 + 1。即 ( 2 + 7 ) % 9 + 1 = 1。github

解题思路

认识数独

首先我以前从未作过数独题目,也不知道数独的规则。从题目描述中了解到了数独棋盘要知足的条件,要每一行、每一列、每个九宫格都有 1-9 不重复的出现,并且左上角必须是 1(我本身的学号算出来的)。算法

资料搜索及算法选择过程

那么接下来就要找一些数独题目来作一下了。我找了一些在线生成数独题目的网站,发现本身并不能作出来,并且根据个人搜索,正常填空的方法并不适合完整的数独棋盘的生成,遂放弃。
在我 Google 的时候发现了一位博主用 Swing 和 Java 写的终盘生成法,分别使用矩阵转换法 [1] 和随机法 [2]。矩阵转换法就是将几个已生成的终盘数独棋盘做为模板,随机选取并进行随机的矩阵变换来生成新的数独棋盘。经计算一个终盘棋盘可经矩阵变换生成 1119744 个不重复且正确的棋盘,刚恰好知足题目 n < 1000000 的要求。当咱们事先输入几个不一样的棋盘,而且生成时随机选取并进行随机的一系列变换就能够生成足够多的棋盘。可是这个方法显然不够随机,我在进行了其余的尝试以后都不成功才会回来采用这个较为简单的方法。同时我也认识到本身程序设计的能力较差,还须要大量的练习,以后会抽时间作一些acm题目来训练本身。文中的随机生成法是随机生成一行来碰运气,我认为不妥,并且效率较为低下。我又考虑了将每一个数依次填入九宫格的方法,好比说先将所有的 1 填入,再将所有的 2 填入,每次填入作一次行列的判断,若可行就填入,不可行就换个地方,直到没法放入,就所有清除,从头开始。再以此类推。我认为这个方法比较稳妥,若是生成的数量多的话能够考虑将已生成的棋盘作矩阵变换,一样是随机而且不重复的,并且更节省时间。固然还要写出来代码看看。编程

算法分析

首先,要有一个生成一系列随机坐标的函数,生成如 (x, y) 的坐标组。x 表示横坐标,y 表示纵坐标。
接着进行判断,当该坐标左边,上边都不重复的话就填入,不然将有冲突的坐标 + 1,依次循环,正常状况下总能够填入。当出现没法填入的状况时,若当前填入的数是 a,则将所有的 a、a - 一、a - 2 置 0,从 a - 2 开始填入,当重复次数到达规定阈值的时候还不能成功填入,就所有清楚,从头开始。此处为溯回的思想。此时不考虑矩阵变换,那么程序大概的流程以下:数组

当前填入数 a = 1;
检查当前九宫格位置(x,y),
    若 x = y = 1 则填入最左上角一格,
    不然生成随机坐标
        检查随机坐标是否合法,      // Judge()
            若不合法则将对应坐标 + 1,
                若两次内成功填入,进入下一个九宫格,重复,
                若没法填入,则清除以前 a , a - 1, a - 2, 从这里从新填入,直到所有的数所有成功填入,
输出,初始化,进入下一次循环

代码实现

因为算法较为复杂,因此从里向外来实现算法。
首先,定义Sudoku[3][3]Pos_s[2]Pos_l[2]分别为保存数独棋盘随机坐标的数组当前九宫格坐标。定义#define random(x) (rand() % x + 1)来生成指定范围内的随机数。
接着,用Judge()函数来判断是否可填入:dom

bool Judge()            //判断是否能够填入 返回为 1 则可填入
{
    int i, j;
    bool flag = 1;    // If Pos is avalible, set flag = 1, else set flag = 0

    for(i = 0; i < Pos_s[0] + Pos_l[0] * 3; i++)
    {
        if(Sudoku[i][Pos_s[1] + Pos_l[1] * 3] == a)
        {
            flag = 0;
            break;
        }
    }
    if(flag == 1)
    {
        for(j = 0; j < Pos_s[1] + Pos_l[1] * 3; j++)
        {
            if(Sudoku[Pos_s[0] + Pos_l[0] * 3][j] == a)
            {
                flag = 0;
            }
        }
    }
    return flag;
}

生成

测试运行

性能分析

参考资料

[1] Swing数独游戏(一):终盘生成之矩阵转换法
[2] Swing数独游戏(二):终盘生成之随机法编程语言

相关文章
相关标签/搜索