ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 Excel Home精品图文教程库
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
300集Office 2010微视频教程 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
楼主: yangyangzhifeng

[分享] 回溯法解数独,平均用时<0.2秒

[复制链接]

TA的精华主题

TA的得分主题

发表于 2013-10-23 14:34 | 显示全部楼层
本帖已被收录到知识树中,索引项:其他结构和算法
暴力破解算法中,目前有两种类型:

剩余有效数检查法:
1. 空格处试填一个有效数,然后检查剩余所有空格的有效数s的状态:
a. 任一空格处有冲突时报错退出,退回上一个空格处 (即 s=""时)
  b. 唯一值时填入s
      (这以后是否立即重新检查前面状态,是算法分歧点)
  c. 有效数>1个 (如s="137")
2. 继续
3. 全部循环完成后,如果有唯一数发生则重新检查一遍,直至无唯一数时进入下一个空格的检查

由于检查繁琐,计算量较大,所以速度不是很好,但一般说算法比较稳定。


第二种算法,就是本楼楼主yangyangzhifeng提出的,
从头开始检查所有空格。
1 to 9 都无效时退回上一个空格

好处是计算过程极其简单,因而有时候效率也挺高,
但因为几乎没有利用到九宫格的唯一性特点,(即没有提前检查后面空格的唯一性)
所以也很有可能落入计算量超大的陷阱。



…………
所以,算法改进的关键是,如何及时检查唯一性,并很好地利用唯一性。

TA的精华主题

TA的得分主题

发表于 2013-10-23 14:39 | 显示全部楼层
我正在思考,把算法1和算法2的特点结合起来,
并且在发现唯一数以后立即回溯之前同行、同列、同宫空格有效剩余s的算法。


这样大概可以减少计算量。

TA的精华主题

TA的得分主题

 楼主| 发表于 2013-10-23 20:47 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
香川群子 发表于 2013-10-23 14:39
我正在思考,把算法1和算法2的特点结合起来,
并且在发现唯一数以后立即回溯之前同行、同列、同宫空格有效 ...

按及时更新最少候选数位置的顺序来解答,好像比较好了
  1. Sub sudoku3()
  2.     Dim br, ar&(1 To 9, 1 To 9), i&, j&, jg&(1 To 81), x&, t&, tt, jwz&(1 To 81), y&, k&
  3.     Dim f_g&(1 To 9, 1 To 9), f_h&(1 To 9, 1 To 9), f_l&(1 To 9, 1 To 9)
  4.     Dim g&(1 To 81), h&(1 To 81), l&(1 To 81)
  5.     tt = Timer
  6.     br = Sheet1.[b2].Resize(9, 9)
  7.     For i = 1 To 9
  8.         For j = 1 To 9
  9.             ar(i, j) = br(i, j)
  10.         Next
  11.     Next
  12.     For i = 1 To 9
  13.         For j = 1 To 9
  14.             x = x + 1
  15.             h(x) = i: l(x) = j
  16.             g(x) = ((i - 1) \ 3) * 3 + (j - 1) \ 3 + 1
  17.             jg(x) = ar(i, j)
  18.             If jg(x) > 0 Then
  19.                 If f_g(g(x), jg(x)) + f_h(h(x), jg(x)) + f_l(l(x), jg(x)) > 0 Then MsgBox "无解": Exit Sub
  20.                 f_g(g(x), jg(x)) = 1
  21.                 f_h(h(x), jg(x)) = 1
  22.                 f_l(l(x), jg(x)) = 1
  23.             Else
  24.                 y = y + 1
  25.                 jwz(y) = x

  26.             End If
  27.         Next
  28.     Next
  29.     j = 0: t = 1
  30.     Do
  31.         j = j + t
  32.         If j > y Then Exit Do
  33.         If t = 1 Then
  34.             jwz(j) = get_wz(ar)
  35.         End If
  36.         x = jwz(j)
  37.         If x <> 0 Then
  38.             For i = jg(x) + 1 To 9
  39.                 If f_g(g(x), i) = 0 Then
  40.                     If f_h(h(x), i) = 0 Then
  41.                         If f_l(l(x), i) = 0 Then
  42.                             jg(x) = i: t = 1: ar(h(x), l(x)) = i
  43.                             f_g(g(x), jg(x)) = 1
  44.                             f_h(h(x), jg(x)) = 1
  45.                             f_l(l(x), jg(x)) = 1
  46.                             Exit For
  47.                         End If
  48.                     End If
  49.                 End If
  50.             Next
  51.         Else
  52.             t = -1
  53.         End If
  54.         If i > 9 Then
  55.             t = -1
  56.             jg(x) = 0: ar(h(x), l(x)) = 0
  57.             If j > 1 Then
  58.                 x = jwz(j - 1)
  59.                 f_g(g(x), jg(x)) = 0
  60.                 f_h(h(x), jg(x)) = 0
  61.                 f_l(l(x), jg(x)) = 0
  62.             Else
  63.                 MsgBox "无解": Exit Sub
  64.             End If
  65.         End If
  66.     Loop
  67.     For i = 1 To 81
  68.         ar(h(i), l(i)) = jg(i)
  69.     Next
  70.     Sheet1.[b12].Resize(9, 9) = ar
  71.     MsgBox Format(Timer - tt, "0.000s ")
  72.     Sheet1.[b12].Resize(9, 9).Interior.ColorIndex = -4142
  73.     Sheet1.[b2].Resize(9, 9).SpecialCells(xlCellTypeConstants, 1).Offset(10).Interior.Color = vbRed
  74. End Sub

  75. Function get_wz(ar&()) As Long
  76.     Dim i&, j&, k, jg&(1 To 9), x&, r&, c&
  77.     For i = 1 To 9
  78.         For j = 1 To 9
  79.             If ar(i, j) = 0 Then
  80.                 For k = 1 To 9
  81.                     If ar(i, k) > 0 Then jg(ar(i, k)) = 1
  82.                     If ar(k, j) > 0 Then jg(ar(k, j)) = 1
  83.                 Next
  84.                 For r = 1 + ((i - 1) \ 3) * 3 To 3 * ((i + 2) \ 3)
  85.                     For c = 1 + ((j - 1) \ 3) * 3 To 3 * ((j + 2) \ 3)
  86.                         If ar(r, c) > 0 Then jg(ar(r, c)) = 1
  87.                     Next
  88.                 Next
  89.                 r = 0
  90.                 For k = 1 To 9
  91.                     r = r + jg(k)
  92.                 Next
  93.                 Erase jg
  94.                 If r > x Then
  95.                     x = r
  96.                     get_wz = (i - 1) * 9 + j
  97.                     If x = 8 Then Exit Function
  98.                 End If
  99.             End If
  100.         Next
  101.     Next
  102. End Function
复制代码

TA的精华主题

TA的得分主题

发表于 2013-10-24 15:58 | 显示全部楼层
准备按以下思路写代码:

第一步:
从第一个位置开始的循环试算检查方法,
但检查值从 1 to 9 改进为 有效数。(这样做本省节省的时间并不很多)

第二步:
接下来,要结合引进【对于新确定唯一数后,立即检查排除同行、同列、同宫中的有效数,
以便不用等待循环就能快速提前得出唯一数。

目前第二步的准备已经做好(快速检查同行、同列、同宫的方法)
但具体检查代码还未加入。

先把半成品代码贴上来。
  1. Option Explicit
  2. Option Base 1
  3. Type zb
  4.     h As Long
  5.     l As Long
  6.     g As Long
  7.     hlg(1 To 20) As Long
  8.     n As Long
  9.     s As String
  10.     s1 As String
  11. End Type
  12. Sub shudu_kagawa3()
  13.     Dim jc&(3, 9, 9), sj(81) As zb
  14.     Dim sj0, xh&(81), yg&(81), gc(82, 3), jg$(81), jl&(81), jc1, jg1, jl1
  15.     Dim i&, j&, k&, l&, m&, n&, r&, s$, t&, u&, v&, tms#
  16.     tms = Timer
  17.    
  18.     sj0 = [b2].Resize(9, 9)
  19.     For i = 1 To 9
  20.         For j = 1 To 9
  21.             k = ((i - 1) \ 3) * 3 + (j - 1) \ 3 + 1
  22.             m = m + 1
  23.             sj(m).h = i
  24.             sj(m).l = j
  25.             sj(m).g = k
  26.             
  27.             n = sj0(i, j)
  28.             If n Then
  29.                 jc(1, i, n) = 1
  30.                 jc(2, j, n) = 1
  31.                 jc(3, k, n) = 1
  32.             Else
  33.                 l = l + 1
  34.                 xh(l) = m
  35.             End If
  36.         Next
  37.     Next
  38.    
  39.     u = 0
  40.     For n = 1 To l
  41.         m = xh(n)
  42.         i = sj(m).h
  43.         j = sj(m).l
  44.         k = sj(m).g
  45.         
  46.         r = 0
  47.         For t = 1 To l
  48.             If t <> n Then
  49.                 If sj(xh(t)).h = i Or sj(xh(t)).l = j Or sj(xh(t)).g = k Then
  50.                     r = r + 1: sj(m).hlg(r) = xh(t)
  51.                 End If
  52.             End If
  53.         Next
  54.         sj(m).n = r
  55.         
  56.         s = ""
  57.         For t = 1 To 9
  58.             If jc(1, i, t) = 0 Then
  59.                 If jc(2, j, t) = 0 Then
  60.                     If jc(3, k, t) = 0 Then
  61.                         s = s & t
  62.                     End If
  63.                 End If
  64.             End If
  65.         Next
  66.         sj(m).s = s
  67.         jg(n) = s
  68.         
  69.         If Len(s) = 1 Then
  70.             u = u + 1
  71.             yg(u) = m
  72. '            jc(1, i, s) = 1
  73. '            jc(2, j, s) = 1
  74. '            jc(3, k, s) = 1
  75. '            Stop
  76.         End If
  77.     Next
  78. '    MsgBox Format(Timer - tms, "0.000s")
  79.    
  80.     gc(1, 1) = jc 'Check
  81.     gc(1, 2) = jg 's
  82.     gc(2, 3) = jl  't
  83.     jc1 = jc
  84.     jg1 = jg
  85.     jl1 = jl
  86.         
  87.     For n = 1 To l
  88.         m = xh(n)
  89.         i = sj(m).h
  90.         j = sj(m).l
  91.         k = sj(m).g
  92.         
  93.         s = jg1(n)
  94. '        If Len(s) = 1 Then
  95. '            t = 0
  96. '        Else
  97.             For t = jl1(n) + 1 To Len(s)
  98.                 v = Mid(s, t, 1)
  99.                 If jc1(1, i, v) = 0 Then
  100.                     If jc1(2, j, v) = 0 Then
  101.                         If jc1(3, k, v) = 0 Then
  102.                             jc1(1, i, v) = 1
  103.                             jc1(2, j, v) = 1
  104.                             jc1(3, k, v) = 1
  105.                             jg1(n) = v
  106.                             jl1(n) = t
  107.                            
  108.                             Exit For
  109.                         End If
  110.                     End If
  111.                 End If
  112.             Next
  113. '        End If
  114.         If t > Len(s) Then
  115.             m = xh(n - 1)
  116.             jc1 = gc(n - 1, 1)
  117.             jg1 = gc(n - 1, 2)
  118.             jl1 = gc(n - 1, 3)
  119.         
  120.             v = Mid(jg1(n - 1), jl1(n - 1), 1)
  121.             jc1(1, sj(m).h, v) = 0
  122.             jc1(2, sj(m).l, v) = 0
  123.             jc1(3, sj(m).g, v) = 0
  124.             n = n - 2
  125.         Else
  126.             gc(n + 1, 1) = jc1 'Check
  127.             gc(n + 1, 2) = jg1 's
  128.             gc(n, 3) = jl1 't
  129.         End If
  130.     Next
  131. '    MsgBox Format(Timer - tms, "0.000s")

  132.     For n = 1 To l
  133.         m = xh(n)
  134.         sj0(sj(m).h, sj(m).l) = jg1(n)
  135.     Next
  136.    
  137.     [b12].Resize(9, 9) = sj0
  138.     MsgBox Format(Timer - tms, "0.0000s")
  139.    
  140. End Sub
复制代码

TA的精华主题

TA的得分主题

发表于 2013-10-24 16:53 | 显示全部楼层
反复检查唯一数的循环过程代码
  1. Do Until u = 0
  2.         k = 0: yg2 = yg1: yg1 = yg
  3.         For i = 1 To u
  4.             n = yg2(i)
  5.             m = xh(n)
  6.             v = jg(n)
  7.             For j = 1 To sj(m).hlg(0)
  8.                 t = sj(m).hlg(j)
  9.                 s = Replace(jg(t), v, "")
  10.                 jg(t) = s
  11.                 If Len(s) = 1 Then
  12.                     k = k + 1
  13.                     yg1(k) = t
  14.                     jc(1, sj(xh(t)).h, s) = 1
  15.                     jc(2, sj(xh(t)).l, s) = 1
  16.                     jc(3, sj(xh(t)).g, s) = 1
  17.                 End If
  18.             Next
  19.         Next
  20.         u = k
  21.     Loop
复制代码

TA的精华主题

TA的得分主题

 楼主| 发表于 2013-10-24 17:13 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
以下题目用用初始代码效果较好,用时1.094s

7*****4**
*1***3***
***2***5*
8***47***
*******62
*********
***1**7**
*6*******
*253*****
用你的半成品测试用时30s,我写的及时更新检查有效数字的代码用时3.719s,现在都不能通吃,不过现在还是及时更新检查有效数字的代码较好

评分

1

查看全部评分

TA的精华主题

TA的得分主题

发表于 2013-10-24 17:14 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
香川群子 发表于 2013-10-23 14:09
呵呵,我们现在的代码中就是使用sj(1 to 81)来记录和处理数据的。


嗯,显然我是说你们可以直接贴81个字符上来,完全没必要截图贴上来~

另外,这种暴力计算有探讨的必要吗?0.1秒和0.01秒的差别?

生成合法数独题的需求:
1、快速确定是否有解
2、快速确定是否解唯一

你们的代码都做不到吧?

至于计算数独的解,需要的是能提示玩家下一步能通过什么逻辑,判断哪一个格子可以填什么数或是去除某个可以填的数。

TA的精华主题

TA的得分主题

 楼主| 发表于 2013-10-24 18:05 | 显示全部楼层
稍微修改就可以实现检查多解,唯一解,无解
  1. Function get_wz(ar&()) As Long
  2.     Dim i&, j&, k, jg&(1 To 9), x&, r&, c&
  3.     x = -1
  4.     For i = 1 To 9
  5.         For j = 1 To 9
  6.             If ar(i, j) = 0 Then
  7.                 For k = 1 To 9
  8.                     If ar(i, k) > 0 Then jg(ar(i, k)) = 1
  9.                     If ar(k, j) > 0 Then jg(ar(k, j)) = 1
  10.                 Next
  11.                 For r = 1 + ((i - 1) \ 3) * 3 To 3 * ((i + 2) \ 3)
  12.                     For c = 1 + ((j - 1) \ 3) * 3 To 3 * ((j + 2) \ 3)
  13.                         If ar(r, c) > 0 Then jg(ar(r, c)) = 1
  14.                     Next
  15.                 Next
  16.                 r = 0
  17.                 For k = 1 To 9
  18.                     r = r + jg(k)
  19.                 Next
  20.                 Erase jg
  21.                 If r > x Then
  22.                     x = r
  23.                     get_wz = (i - 1) * 9 + j
  24.                     If x > 7 Then Exit Function
  25.                 End If
  26.             End If
  27.         Next
  28.     Next
  29. End Function
  30. Sub sudoku4() '检查多解,唯一解,无解
  31.     Dim br, ar&(1 To 9, 1 To 9), i&, j&, jg&(1 To 81), x&, t&, tt, jwz&(1 To 81), y&, k&
  32.     Dim f_g&(1 To 9, 1 To 9), f_h&(1 To 9, 1 To 9), f_l&(1 To 9, 1 To 9), zzz&
  33.     Dim g&(1 To 81), h&(1 To 81), l&(1 To 81)
  34.     tt = Timer
  35.     br = Sheet1.[b2].Resize(9, 9)
  36.     For i = 1 To 9
  37.         For j = 1 To 9
  38.             ar(i, j) = br(i, j)
  39.         Next
  40.     Next
  41.     For i = 1 To 9
  42.         For j = 1 To 9
  43.             x = x + 1
  44.             h(x) = i: l(x) = j
  45.             g(x) = ((i - 1) \ 3) * 3 + (j - 1) \ 3 + 1
  46.             jg(x) = ar(i, j)
  47.             If jg(x) > 0 Then
  48.                 If f_g(g(x), jg(x)) + f_h(h(x), jg(x)) + f_l(l(x), jg(x)) > 0 Then MsgBox "无解": Exit Sub
  49.                 f_g(g(x), jg(x)) = 1
  50.                 f_h(h(x), jg(x)) = 1
  51.                 f_l(l(x), jg(x)) = 1
  52.             Else
  53.                 y = y + 1
  54.                 jwz(y) = x

  55.             End If
  56.         Next
  57.     Next
  58.     j = 0: t = 1
  59.     Do
  60.         j = j + t
  61.         If j > y Then
  62.             x = jwz(j - 1): t = -1
  63.             f_g(g(x), jg(x)) = 0
  64.             f_h(h(x), jg(x)) = 0
  65.             f_l(l(x), jg(x)) = 0
  66.             zzz = zzz + 1
  67.             If zzz > 2 Then MsgBox "2个以上解": Exit Sub
  68.         Else
  69.             If t = 1 Then
  70.                 jwz(j) = get_wz(ar)
  71.             End If
  72.             x = jwz(j)
  73.             If x <> 0 Then
  74.                 For i = jg(x) + 1 To 9
  75.                     If f_g(g(x), i) = 0 Then
  76.                         If f_h(h(x), i) = 0 Then
  77.                             If f_l(l(x), i) = 0 Then
  78.                                 jg(x) = i: t = 1: ar(h(x), l(x)) = i
  79.                                 f_g(g(x), jg(x)) = 1
  80.                                 f_h(h(x), jg(x)) = 1
  81.                                 f_l(l(x), jg(x)) = 1
  82.                                 Exit For
  83.                             End If
  84.                         End If
  85.                     End If
  86.                 Next
  87.                 If i > 9 Then
  88.                     t = -1
  89.                     jg(x) = 0: ar(h(x), l(x)) = 0
  90.                     If j > 1 Then
  91.                         x = jwz(j - 1)
  92.                         f_g(g(x), jg(x)) = 0
  93.                         f_h(h(x), jg(x)) = 0
  94.                         f_l(l(x), jg(x)) = 0
  95.                     Else
  96.                         Exit Do
  97.                     End If
  98.                 End If
  99.             Else
  100.                 t = -1
  101.             End If
  102.         End If
  103.     Loop
  104.     If zzz = 0 Then MsgBox "无解" Else MsgBox "唯一解"
  105. End Sub
复制代码

TA的精华主题

TA的得分主题

发表于 2016-3-5 14:30 | 显示全部楼层
本帖是VBA暴力解代码的精华帖。

TA的精华主题

TA的得分主题

发表于 2016-3-5 21:41 | 显示全部楼层
{:soso__3409329614010722382_4:},先收了!
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-6-16 07:04 , Processed in 0.033195 second(s), 8 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表