python deepcopy函数_用Python解数独[6]:递归获得最终答案

352ca3fdb0d7ddfbc0905ae69f87b6dc.png

目录

  1. 用Python解数独[0]
  2. 用Python解数独[1]:求每个单元格的行值域
  3. 用Python解数独[2]:求列值域和九宫格值域
  4. 用Python解数独[3]:求总值域
  5. 用Python解数独[4]:缩减值域
  6. 用Python解数独[5]:检测唯一值缩减值域
  7. 用Python解数独[6]:递归获得最终答案
  8. 用Python解数独[7]:递归(完结篇)

[2][1] 解决数独问题基本思路

7、递归获得最终答案

上一回我们对于值域列表缩减函数进行了改造,增加了检测唯一值的方法,但最终我们依然没有得到答案,还有很多单元格的答案没有确定,应该怎么办呢?

6a157f48c04066e0b54f066e4788662b.png

在当前这种情况下,我们已经无法从数独中直接确定某个单元格的答案了,但是我们可以用试验的办法,去验证某个单元格的答案是值域里的哪一个值。我们以第7行第7列单元格为例,我们假设它的值是1,则这个变化会引起一系列的变化,最终我们得到这个:

d649d7794e62f66e5c5073fac349ac6f.png

在第二个九宫格出现了2个7,因此我们可以判断第7行第7列的值不是1,而应该是6。我们通过这种测试验证的方法获得了某个单元格的答案。我们现在需要用代码来实现:

# 主函数,输入值域列表,如遇到多个取值的单元格,依次尝试值域里的每个值,通过递归的方法检测值是否正确

这段代码其实还是挺复杂的,容我细细解读:

# 主函数,输入值域列表,如遇到多个取值的单元格,依次尝试值域里的每个值,通过递归的方法检测值是否正确
  • 我们设置i和j两个循环,是为了遍历total_value_range里的每一个元素
  • 当len(total_value_range[i][j]) = 1时,也就是说这个单元格是已知单元格,取值已经确定了;如果len(total_value_range[i][j]) > 1,这个单元格是未知单元格,值域列表有多个取值;
  • 对于未知单元格,我们遍历它的值域,同时拷贝一份total_value_range,并把值域里的值赋给test_value[i][j],开始进行“试验”,看test_value[i][j]里的哪一个值是正确的;
# 检查行值域列表是否合法
  • 赋值之后,我们立即使用之前的generator_soduku()和reduce_totalValueRange()方法,基于已有条件生成一个最新的值域列表;
  • 然后我们需要做的是,用soduku_checkRepeat()方法检验当前的值域列表是否合法,soduku_checkRepeat()方法的原理也很简单:
    • 首先我们写出一个检查行值域列表是否合法的函数:将一行已知单元格都选出放到一个列表里,检查列表是否有重复值;
    • 有了行值域检查函数,只需将数独进行行列转换和九宫格转换然后分别进行检测,如果三项检测均为True,则最后返回True,有一项False,最后返回False
  • 如果soduku_checkRepeat()显示当前值域列表合法,则使用sodukuRate()方法检测当前值域列表每个单元格是否都是已知单元格(各单元格值域长度均为1)
    • 若每个单元格值域长度均为1,则说明已经得到最终正确答案,则返回test_value,即最终正确答案;
    • 若sodukuRate(test_value)不为1,则说明经过一番操作后还未得到正确答案,或者得到错误答案,因此我们将当前的值域列表test_value作为参数,用if判断trial(test_value),这个就用上了递归的概念,我们稍后详细解释
  • 如果soduku_checkRepeat()显示当前值域列表不合法,则说明total_value_range[i][j]当前的取值k不正确,我们continue,继续循环;
  • 如果for k in total_value_range[i][j],这个循环结束了,说明所有的取值k都是导向错误的结果(在第一层trial()是不会出现的,会出现在第二层trial()时),则返回False;

最终运行代码,得到了结果

PS 

把全部源码展示出来:

import 

下一期我们将详细解释这个利用了递归的函数,具体是如何运行的,我们这个用Python解数独栏目也将迎来尾声。


下一篇链接:用Python解数独[7]:递归(完结篇)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值