回溯算法解数独问题

好久没写算法了,浅解个数独

本篇代码以伪代码为主,主要讲解解题思路


规则介绍:

首先数独的游戏规则,每个九宫格 每一行 每一列 每个数字只能出现一次(1-9)

开局时会生成一些不能改变数字的格子

按规则填满所有格子为过关

图下所示为前几天朋友卡关了的状态:

例如第二行第一列有一个固定的5,在它的九宫格里就不能再出现另一个5

第二行也不能再出现5,第一列也不能再出现5


回溯思路:

我需要一个方法能够解这道题,我称呼他为方法A

需要调用方法A就能自动解开这道题,但是按照回溯算法的解题思路,方法A中的核心代码只需要解开一个格子的值,然后在下一个格子的位置再调用方法A

就有了如下伪代码:

布尔 方法A(int x,int y){
//此处先省略解开当前格子的代码 传入的参数为格子的坐标
返回 方法A(x,y+1);
}

这样的话,只需要调用方法A(0,0) 在解开一个格子后,他会自动去解下一个坐标的格子

最终返回true表示解开了这道数独,否则没解开

但是一行只有9个格子,一共9列,所以添加如下代码自动换行(添加到方法顶端,先判断是否越界再运行核心代码):

复制代码
if (x > 8) {
    return true;
}
if (y > 8) {
    return 方法A(x + 1, 0);
}
复制代码

现在这个方法已经会自动寻找下一个格子了

但是如果这个格子里的数值是不能修改的,就应该跳过这个格子

我的方法是开始运行前就遍历一遍格子,如果值不为0(开始求解前就有值),就把这个格子标记为不可变

if(此格子的数值不可变){
    return 方法A(x,y+1);
}

即使这里的y+1超过了下标上限,运行到下一个格子的时候也会自动修正


以上是部分回溯,当然后续还会根据情况修改

解题思路:

说明:我将开始解题前就有值的格子称为不可变格子,因为里面的值是固定的,不能改变

1、首先找到这个格子能填入的所有数值

以图中(0,0)为例,第0下标列中有5,4,1,7 第0下标行中有6,3,2 所在的九宫格中有5,1,7 所以这个格子只能填入8,9

提醒:

这个格子所在的九宫格里所有格子的特征:格子的行号除以3相等 格子的列号除以3相等

(左上角这个九宫格里的任何格子 行号除以3都为0 列号除以3都为0 而下面的九宫格行号除以3为1 列号除以3为0)

 

2、依次尝试能填的所有数字

先填入8,然后进行下一个格子,运行中如果发现下一个格子怎么填都不正确,说明前面的格子有存在错误的,则值清0,返回前面的格子,接着试下一个答案

例如:

(0,0)格子填入8,进入下一个格子 即调用了方法A(0,1) (0,1)格子中只能填入4,9 结果发现填哪个都不行,只能把自己重新赋值0 返回false

(0,0)接收到false 继续尝试下一个 尝试填入9 继续调用方法A(0,1)

以此类推,直到得到正确答案 如果所有值都试完了 都没有正确答案 则返回false

所以回溯部分的代码也需要一些修改

复制代码
for(可填入的数字的集合){
格子(x,y)
=可填入的数字
if(方法A(x,y+1)){ return true; } }
格子(x,y)=0
return false;
复制代码

运行起来大概是这个样子

如果得到正确的解,会从最后一个格子返回 true

而前面的格子都是使用if(方法A(x,y+1))调用的后面的格子

接收到true后也会返回true 直到最初的方法A(0,0)也返回true

如果所有的方案都无法得到解 尝试完所有方案后 也会依次返回false

 

posted @   unIlIl  阅读(278)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
历史上的今天:
2021-11-12 回溯解八皇后问题
点击右上角即可分享
微信分享提示