解数独 算法 leetCode 37题 c++

题目

 

解题思路
一、思路说明:
        每一个待填的格子中,所能填的数字同时被该格子所在行、列、33块上已有的数字所限制。
如果使用传统方法,在每个代填的格子中遍历每个数时,都得遍历整行、整列、整块,看有没有与该数相同的数字,如果有则不能取该值,没有则选择该值,继续去判断下一个格子。此种方法在同一行、同一列、同一块中重复遍历判断。造成了时间的浪费,非常滴不银杏化。
        不妨列三个数组、分别保存该行、列、33块上已经出现过的数字(记为false)和还能填的数字(记为true),判断某个格子能不能填某值时,只需找到该值和坐标对应的行、列、块数组,从三个数组中取出来的值都为true则在该坐标内能填入该数字。
        这样做的好处是,同一行判断某个数字能不能填时,不同的格子不用重复遍历所在行、列、块进行判断。
二、数据说明:
        利用布尔三个数组保存行、列、块中已经出现过的数字
yFree[n][num]:如果在第n行有num,则为False,否则为True,表示单从行看这一行都可以填入num。
xFree[n][num]:如果在第n列有num,则为False,否则为True,表示单从列看这一列都可以填入num。
blockFree[m][n][num]:如果在第m,n个块里有num,则为False,否则为True。
三、函数与类说明:
1、freeNum类:用来保存三个数组的类。
2、freeNum.isFree(u16 x,u16 y,u16 num):用来判断第y行、x列能否填入num数字,能则返回true。
3、freeNum.setFaulse(u16 x,u16 y,u16 num):将y行、x列的num数字设置成False,有三个作用:
①整个y行都不能再填入num。
②整个x列都不能再填入num。
③整个(x,y)所在的3*3块都不能再填入num。
4、freeNum.setValue(u16 x,u16 y,u16 num):功能与setFaulse相反。用于遍历下个数字时,将上个已遍历的数擦除。
5、giveTortoise(int count);递龟(递归)函数(没错,取名就是这么直白)。用于递归遍历每个格子,将需要填数的格子依次填入可填入的数字,然后递归调用下一个格子。直到最后一个格子有解返回true,如果该格子中没有可填入的数或填入任何数字后级都无解,则返回false,交给前级继续遍历剩下的数。
四、程序说明:
1、初始化FreeNum类的对象。数组所有值幅true。然后遍历已经填好的数,每个已填的数将其所在行、列、块禁填(反应在数据上就是将三个数组对应的位置改成false)。
2、行优先递归每个格子,如果该格子有数则直接递归到下一个数,直到最后一个格子有解,则保存整条递归路径,输出。

代码:

#define u16 unsigned short int
class freeNum
{
public:
    bool xFree[9][9]={};
    bool yFree[9][9]={};
    bool blockFree[3][3][9]={};
    freeNum()
    {
        for(int i=0;i<81;i++)
        {
            xFree[i%9][i/9]=true;
            yFree[i%9][i/9]=true;
            blockFree[i/9/3][i/9%3][i%9]=true;
        }
    }
    bool isFree(u16 x,u16 y,u16 num)
    {
        if(xFree[x][num-1]==true && yFree[y][num-1]==true && blockFree[y/3][x/3][num-1]==true)
        {
            return true;
        }
        else return false;
    }
    void setFalse(u16 x,u16 y,u16 num)
    {
        //cout<<x<<" "<<y<<" "<<num<<"\n";
        xFree[x][num-1] = false;
        yFree[y][num-1] = false;
        blockFree[y/3][x/3][num-1] = false;
    }
    void setTrue(u16 x,u16 y,u16 num)
    {
        xFree[x][num-1] = true;
        yFree[y][num-1] = true;
        blockFree[y/3][x/3][num-1] = true;
    }
};

class Solution {
public:
    u16 array[9][9]={0};
    freeNum free;
    bool giveTortoise(int count)
    {
        int nowx = count%9;
        int nowy = count/9;
        if(array[nowy][nowx] != 0)
        {
            if(count ==80)return true;
            else return giveTortoise(count+1);
        }
        for(int i=1;i<10;i++){
            if(free.isFree(nowx,nowy,i))
            {
                free.setFalse(nowx,nowy,i);
                if(count == 80)
                {
                    array[nowy][nowx] = i;
                    return true;
                }
                else 
                {
                    if(giveTortoise(count+1))
                    {
                        array[nowy][nowx] = i;
                        return true;
                    }
                    free.setTrue(nowx,nowy,i);
                }
            }
        }
        return false;
    }

    void solveSudoku(vector<vector<char>>& board) {
        for(int y=0;y<9;y++)
        {
            for(int x=0;x<9;x++)
            {
                if(board[y][x]=='.')array[y][x]=0;
                else 
                {
                    array[y][x]=board[y][x]-48;
                    free.setFalse(x,y,array[y][x]);
                }
            }
        }
        giveTortoise(0);
        for(int y=0;y<9;y++)
        {
            for(int x=0;x<9;x++)
            {
                board[y][x]=array[y][x]+48;
            }
        }

    }
};

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值