ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 效率神器,一键搞定繁琐工作
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
让更多数据处理,一键完成 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
查看: 16218|回复: 43

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

[复制链接]

TA的精华主题

TA的得分主题

发表于 2013-10-20 13:34 | 显示全部楼层 |阅读模式
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
本帖已被收录到知识树中,索引项:其他结构和算法
本帖最后由 yangyangzhifeng 于 2013-10-24 12:55 编辑
  1. Sub sudoku()
  2.     Dim ar, i&, j&, jg&(1 To 81), x&, t&, tt
  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.     ar = Sheet1.[a1:i9]
  7.     For i = 1 To 9
  8.         For j = 1 To 9
  9.             x = x + 1
  10.             h(x) = i: l(x) = j
  11.             g(x) = ((i - 1) \ 3) * 3 + (j - 1) \ 3 + 1
  12.             jg(x) = ar(i, j)
  13.             If jg(x) > 0 Then
  14.                 If f_g(g(x), jg(x)) + f_h(h(x), jg(x)) + f_l(l(x), jg(x)) > 0 Then MsgBox "无解": Exit Sub
  15.                 f_g(g(x), jg(x)) = 1
  16.                 f_h(h(x), jg(x)) = 1
  17.                 f_l(l(x), jg(x)) = 1
  18.             End If
  19.         Next
  20.     Next
  21.     x = 1: t = 1
  22.     Do
  23.         If x = 0 Then MsgBox "无解": Exit Sub
  24.         If x > 81 Then Exit Do
  25.         If ar(h(x), l(x)) = 0 Then
  26.             For i = jg(x) + 1 To 9
  27.                 If f_g(g(x), i) + f_h(h(x), i) + f_l(l(x), i) = 0 Then
  28.                     If jg(x) > 0 Then
  29.                         f_g(g(x), jg(x)) = 0
  30.                         f_h(h(x), jg(x)) = 0
  31.                         f_l(l(x), jg(x)) = 0
  32.                     End If
  33.                     jg(x) = i: t = 1
  34.                     f_g(g(x), jg(x)) = 1
  35.                     f_h(h(x), jg(x)) = 1
  36.                     f_l(l(x), jg(x)) = 1
  37.                     Exit For
  38.                 End If
  39.             Next
  40.             If i > 9 Then
  41.                 t = -1
  42.                 If jg(x) > 0 Then
  43.                     f_g(g(x), jg(x)) = 0
  44.                     f_h(h(x), jg(x)) = 0
  45.                     f_l(l(x), jg(x)) = 0
  46.                     jg(x) = 0
  47.                 End If
  48.             End If
  49.         End If
  50.         x = x + t
  51.     Loop
  52.     For i = 1 To 81
  53.         ar(h(i), l(i)) = jg(i)
  54.     Next
  55.     Sheet2.[a1:i9] = ar
  56.     MsgBox Format(Timer - tt, "0.000s "): Sheet2.Activate
  57.     Sheet2.Cells.Font.Bold = False
  58.     Sheet2.Range(Sheet1.Range("a1:i9").SpecialCells(xlCellTypeConstants, 1).Address(0, 0)).Font.Bold = True
  59. End Sub
复制代码
shudu.rar (13.62 KB, 下载次数: 155)
改良版
  1. Sub sudoku2()
  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.             If i > 9 Then
  52.             t = -1
  53.             jg(x) = 0: ar(h(x), l(x)) = 0
  54.             If j > 1 Then
  55.                 x = jwz(j - 1)
  56.                 f_g(g(x), jg(x)) = 0
  57.                 f_h(h(x), jg(x)) = 0
  58.                 f_l(l(x), jg(x)) = 0
  59.             Else
  60.                 MsgBox "无解": Exit Sub
  61.             End If
  62.         End If
  63.         Else
  64.             t = -1
  65.         End If
  66.         
  67.     Loop
  68.     For i = 1 To 81
  69.         ar(h(i), l(i)) = jg(i)
  70.     Next
  71.     Sheet1.[b12].Resize(9, 9) = ar
  72.     MsgBox Format(Timer - tt, "0.000s ")
  73.     Sheet1.[b12].Resize(9, 9).Interior.ColorIndex = -4142
  74.     Sheet1.[b2].Resize(9, 9).SpecialCells(xlCellTypeConstants, 1).Offset(10).Interior.Color = vbRed
  75. End Sub

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

评分

2

查看全部评分

TA的精华主题

TA的得分主题

发表于 2013-10-20 13:43 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
留印学习{:soso_e183:}

TA的精华主题

TA的得分主题

发表于 2013-10-21 13:01 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2013-10-21 13:55 | 显示全部楼层

TA的精华主题

TA的得分主题

 楼主| 发表于 2013-10-21 14:25 | 显示全部楼层
jiangdong110 发表于 2013-10-21 13:55
晕,太高深了!

思路如下:
由于数独都是填1-9的数字,用3个数组 f_h&(1 To 9, 1 To 9), f_l&(1 To 9, 1 To 9),f_g&(1 To 9, 1 To 9)可以记录行,列及宫格的数字
每尝试填上一个位置的数字,就更新这3个标记数组,当尝试到9后还不能满足条件则退回上一个位置,否则尝试下一个位置,直到填好最后一个
位置(有解)或退回第一个位置之前(无解)
g&(1 To 81), h&(1 To 81), l&(1 To 81)记录81个位置在3个标记数组中对应的第一维下标,可减少计算量

TA的精华主题

TA的得分主题

发表于 2013-10-21 17:12 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
不错的思路,减少了很多重复计算无用功。

另外,长整形数组记录状态也确实可以提高速度。


我有空按照你的思路也来写一个……估计凭我的经验,速度也许还可以再提高些。


结论:思路其实最重要。




TA的精华主题

TA的得分主题

发表于 2013-10-21 17:18 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
本帖最后由 香川群子 于 2013-10-22 00:59 编辑

按你的思路代码改写成功!

对于自由度较大(可能性较多的)计算尤其效果最佳。

速度比你的快,有时候可以快一倍。(一般大约10-50%)


shudu3.rar (24.12 KB, 下载次数: 140)



评分

1

查看全部评分

TA的精华主题

TA的得分主题

发表于 2013-10-21 20:54 | 显示全部楼层
香川群子 发表于 2013-10-21 17:18
不错的思路,减少了很多重复计算无用功。

另外,长整形数组记录状态也确实可以提高速度。

思路决定出路!

TA的精华主题

TA的得分主题

发表于 2013-10-21 22:10 | 显示全部楼层
很好,学习,下次不用再为数独冥思苦想了,值得研究,这个家中开了好头。

TA的精华主题

TA的得分主题

发表于 2013-10-21 23:18 | 显示全部楼层
用了自定义类型解决了行、列、宫的坐标
  1. Option Base 1
  2. Type zb
  3.     h As Long
  4.     l As Long
  5.     g As Long
  6. End Type

  7. Sub shudu_kagawa2()
  8.     Dim jl(81), jl_h&(9, 9), jl_l&(9, 9), jl_g&(9, 9), sj(81) As zb
  9.     Dim sj0, sj1, i&, j&, k&, l&, tms#
  10.     tms = Timer
  11.    
  12.     For i = 1 To 81
  13.         sj(i).h = (i - 1) \ 9 + 1
  14.         sj(i).l = (i - 1) Mod 9 + 1
  15.         sj(i).g = ((i - 1) \ 9 \ 3) * 3 + ((i - 1) Mod 9) \ 3 + 1
  16.     Next
  17.    
  18.     sj0 = [b2].Resize(9, 9)
  19.     For i = 1 To 81
  20.         j = sj0(sj(i).h, sj(i).l)
  21.         If j Then
  22.             jl_h(sj(i).h, j) = 1
  23.             jl_l(sj(i).l, j) = 1
  24.             jl_g(sj(i).g, j) = 1
  25.         Else
  26.             k = k + 1
  27.             jl(k) = i
  28.         End If
  29.     Next
  30. '    MsgBox Format(Timer - tms, "0.000s")
  31.    
  32.     ReDim js&(k)
  33.     For k = 1 To k
  34.         i = jl(k)
  35.         For j = js(k) + 1 To 9
  36.             If jl_h(sj(i).h, j) + jl_l(sj(i).l, j) + jl_g(sj(i).g, j) = 0 Then
  37.                 jl_h(sj(i).h, j) = 1
  38.                 jl_l(sj(i).l, j) = 1
  39.                 jl_g(sj(i).g, j) = 1
  40.                 js(k) = j
  41.                
  42. '                sj1 = sj0
  43. '                For l = 1 To k
  44. '                    i = jl(l)
  45. '                    sj1(sj(jl(l)).h, sj(jl(l)).l) = js(l)
  46. '                Next
  47. '                [b12].Resize(9, 9) = sj1
  48.                
  49.                 Exit For
  50.             End If
  51.         Next
  52.         If j = 10 Then
  53.             js(k) = 0
  54.             i = jl(k - 1)
  55.             j = js(k - 1)
  56.             
  57.             jl_h(sj(i).h, j) = 0
  58.             jl_l(sj(i).l, j) = 0
  59.             jl_g(sj(i).g, j) = 0
  60.             k = k - 2
  61.         End If
  62.     Next
  63. '    MsgBox Format(Timer - tms, "0.000s")
  64.    
  65.     For k = 1 To k - 1
  66.         i = jl(k)
  67.         sj0(sj(i).h, sj(i).l) = js(k)
  68.     Next
  69.     [b12].Resize(9, 9) = sj0
  70.     MsgBox Format(Timer - tms, "0.0000s")
  71.    
  72. End Sub
复制代码

评分

1

查看全部评分

您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

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

GMT+8, 2024-12-4 01:24 , Processed in 0.036974 second(s), 12 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

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

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

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