第三次软件工程实践作业

我的GitHub:mmbhwhh

PSP

PSP 预估耗时(小时) 实际耗时(小时)
计划 2 3
估计这个任务需要多少时间 16 20
开发 1 2
需求分析 (包括学习新技术) 2 2
生成设计文档 2 3
设计复审 3 3
具体设计 2 3
具体编码 3 5
代码复审 3 3
测试(自我测试,修改代码,提交修改) 1 2
报告 2 3
过程改进计划 1 2
总计 22 31

思考

开始拿到题目的时候,以为是我想象中的数独,就简单的想着只要把每个已经确定的数对它当前所在的行、列、宫格的影响扩散出去,题目又说给的数独都是唯一解的,这更加让我确信用我的思路可以解出来,然后就试了试。

刚开始的思路

大体和第一位交作业的莫多同学一样,就是对数独遍历两次,第一次找到入口(因为题目说测试的数据都是唯一解),找到一个确定的点,然后将它的影响扩散给行、列、宫格,最终就会将整个表格填满。写了很久的代码,却发现我的思路只能填写一部分数据,没玩过数独的我还是太嫩了,后面冷静下来思考一番,如果数独有这么简单还叫什么数独呢,从我的那些错误的数据我知道了,尽管一个数独只有一个解,但是它也不一定可以用逻辑直接确定全部的值,因为我从我错误的代码打出来的错误结果显示,没填的那部分数据的确不能确定,必须要填入数值进去试探,虽然填的数字合法,但是解不出来。这结果让我原地自闭。

第二次想法

经历了上次的教训,索性直接用暴力的办法解这道题。思路就是从第一个格子一直找到最后一个格子,如果找到了空格子,那就给它赋上合法的数值,然后继续找,如果找不到了就出现了两种情况。一是已经填完了,结果出来了,并且它是合法的也就是它的解了;二是,找不到合法的值了,但是它却还是空着的,说明前面赋的值不对,此时再回去改,直到正确为止。代码如下:

check(u,i)函数是检测在u(把宫格的格子编号,从左上角为起始点一直到右下角,例如9宫格就有1、2、3...........80、81的编号)的位置,填入i合不合法

bool check(int u, int t)
{
    int x, y;
    x = (u - 1) / type + 1;
    y = (u - 1) % type + 1;//找到u这个位置的坐标
    for (int i = 1; i <= type; i++)
    {
        if (gg[x][i] == t && i != y)    return false;
        if (gg[i][y] == t && i != x)   return false;

    }//判断这个位置填入的数会不会与行和列冲突

    if (type == 4 || type == 6 || type == 8 || type == 9)
    {
        int xs, ys;
        int beginx, beginy;//当前坐标所在宫格的左上角坐标,可当做起始坐标
        switch (type)//判断宫格的规模
        {
        case 4:
            xs = 2;
            ys = 2;
            break;
        case 6:
            xs = 2;
            ys = 3;
            break;
        case 8:
            xs = 4;
            ys = 2;
            break;
        case 9:
            xs = 3;
            ys = 3;
            break;
        }
        int flogx = xs;
        int flogy = ys;//flogx和flogy只是待会下面用到的循环次数
        beginx = (x - 1) / xs * xs + 1;
        beginy = (y - 1) / ys * ys + 1;
        for (int i = beginx; flogx > 0; flogx--, i++)
        {

            for (int j = beginy; flogy > 0; flogy--, j++)
            {
                if (t == gg[i][j] && (x != i || y != j))    return false;
            }
            flogy = ys;
        }
        flogy = xs;
    }//判断此位置填入的数会不会与宫格里的冲突

    return true;//能走到这里说明填的数合法

}

上面的check函数会在dfs函数中用到,dfs的作用就是搜索

bool dfs(int u)
{
    if (u > type*type)  return true;//迭代到编号以外,说明前面填的数都是合法的
    int x, y;
    x = (u - 1) / type + 1;
    y = (u - 1) % type + 1;//给它坐标化
    if (gg[x][y])   return dfs(u + 1);//如果这个位置有数字,就去下一个点
    else {
        for (int i = 1; i <= type; i++)
        {
            if (check(u, i))
            {

                gg[x][y] = i;
                if (dfs(u + 1))return true;
                gg[x][y] = 0;
            }
        }//这个位置还没填入数据,就随便给它一个值,然后再执行下一个点,如果下一个点不可以了就会回来这个点重新赋值
        return false;
    }
}

测试结果


性能测试

猜你喜欢

转载自www.cnblogs.com/xp3736----/p/11584704.html