数独算法
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
数独算法
数独问题及计算机求解
lscill
数独SuDoku
数独的由来 数独的经典算法 数独的计算机求解 数独的并行求解
什么是Sudoku??数独??
数独的由来
数独是一种源自18世纪末的瑞士,后在美 国发展、并在日本得以发扬光大的数学智力拼 图游戏。拼图是九宫格(即3格宽×3格高)的 正方形状,每一格又细分为一个九宫格。在每 一个小九宫格中,分别填上1至9的数字,让整 个大九宫格每一列、每一行的数字都不重复。
来自百度文库
数独的算法—候选数法
现在需要做的只是对这几种方法进行整合。
唯一候选数法”是最简便、最直接、最有效的 算法 ,因此 ,只要条件成立,就一定要用;搜索算 法具有一定的盲目性 ,但它的实现是无条件的 , 在经过优化后 ,其速度也不慢“;
隐性惟一候选数法”虽然直接 ,但由于其条件 判定较复杂 ,因此它可以作为减少搜索深度的 辅助算法。
数独的计算机算法
回溯法的基本思想下面给出详细的步骤与代码。
(1)按下标的由低到高扫描 fix数组,将值为 0的位置记录进stack数 组,记录的顺序也是由低到高。最后,整型量 max记录下:fix数组中 为 0位置的个数再加 1。
(2)整型量 top初始化为 0,即把 stack看作栈(虽然 stack数组的内 容永远不会变,但 top的增减仍代表了进栈和出栈的操作),top记录 的是栈顶。
(5)flag为假,说明是经过了回退才达到现在这个栈顶的,那么:若 仍然没有可能的数字可以应用在当前栈顶所保存的位置上,那么 继续执行出栈操作,即:fix数组和 sd数组的该位置重设为 0,top减 1;否则将遇到的第一个可能数字应用到该位置,即:再设好 sd数 组和 fix数组,将 top加 1,并将 flag置为真。本轮循环体结束,继续 下一轮的循环。
数独的计算机算法
(4)flag为真,说明栈顶(top)是经过正常的假设而达到的,并非由回 退达到,那么:根据 possible数组以及 beExist函数(参见 3.2节), 对栈顶所保存位置的可能出现的数字进行判断,把遇到的第一个 可能数字设置进 sd数组,并把 fix数组的该位置的值设为 1,并判 断是否已经解出结果,即 top和 max相等否,若相等,则打印结果 并退出死循环;若发现 1-9都不可能应用在栈顶所保存的位置,则 说明前面的假设有错误,此时应当回退,即:fix数组和 sd数组的该 位置重设为 0,top减 1,并将 flag置为假。本轮循环体结束,继续 下一轮的循环。
数独的由来
1783年,瑞士数学家莱昂哈德·欧拉发明了 一种当时称作“拉丁方块”的游戏,这个游 戏是一个n×n的数字方阵,每一行和每一列 都是由不重复的n个数字或者字母组成的。
用从1开始的n个连续正整数排成n行n列的方 阵,如果每一行和每一列都没有重复的数, 就称为一个n阶拉丁方。因为这样的方阵最早 填充的是拉丁字母,故名。 下面是一个3阶拉丁方
使用直观法时,大部分的时间 应该都在使用基础摒除法,但
有些较困难的数独题目,不时 会出现以基础摒除法将找不到 解的情况,这时就是唯余解法 上场应用的机会
数独的算法—候选数法
数独的解谜技巧,刚开始发展时,以直观式的唯一解 法及摒除法为主,对于一般简易级或中级的数独谜题, 通常已游刃有余。 但是唯一解法及初阶的摒除法在使 用上有其限制,在中、高级的题目中有时将无用武之 地。但高阶的摒除技巧又十分繁难。
基础摒除法>> 唯一解法。 区块摒除法。 唯余解法。 单元摒除法。 矩形摒除法。 余数测试法。
基础摒除法
基础摒除法虽然简单,但在实际应用时,仍然可 分成三个部分:
行摒除:因为同一行不能有两个相同的数字,所以当 某个数字已在某行中出现时,该行再填入该数字的可能性 就应该被摒除掉。
列摒除:因为同一列不能有两个相同的数字,所以当 某个数字已在某列中出现时,该列再填入该数字的可能性 就应该被摒除掉。
(3)int possible[82][10];该数组的用途是记录所有未确定数字的所有 可能性 记录方法是 数组各元素的值在初始化时被初始化为与其第 二维的下标一致 即 0-9;中间计算过程中,若发现第一维某位置的某 种可能性已不复存在 则将第一维下标是该位置而第二维下标是该 不再可能的数字的元素值改为-1。
否则 回溯
数独的算法—候选数法
当候选数表的某一个区域(行、列或九宫格)中 某一个数字只存在于一个格中 ,那么那个数字 必应填入此格。这是因为本数字必须出现在这 一区域 ,进而只能出现在这一格中 ,这种解法称 为“隐性唯一候选数法”。
每次尝试只需找到一个使 N[i ,x] = 1 的 i 和 x 表示的区域 ,再找到那个区域中可填入i 的方 格 ,一次计算机模拟的“隐性唯一候选数法” 就完成了。
123 231 312
数独的问题
拉丁方不一定是数独的解 数独问题不可由数学公式推算
数独的人工算法
直观法&摒除法 候选数法 不动点法
数独的算法—直观法
直观法的特性: 不需任何辅助工具就可应用。所以要玩报
章杂志上的数独谜题时,只要有一枝笔就可 以开始了.
数独的算法—直观法
直觀法的主要的技巧:
数独的由来
数独前身为“九宫格”,最早起源于中国。 数千年前,我们的祖先就发明了洛书,其特 点较之现在的数独更为复杂,要求纵向、横 向、斜向上的三个数字之和等于15,而非简 单的九个数字不能重复。儒家典籍《易经》 中的“九宫图”也源于此,故称“洛书九宫 图”。而“九宫”之名也因《易经》在中华 文化发展史上的重要地位而保存、沿用至今。
宫摒除:因为同一个九宫格不能有两个相同的数字, 所以当某个数字已在某个九宫格中出现时,该九宫格再填 入该数字的可能性就应该被摒除掉。
唯一解法
唯余解
当数独谜题中的某一个宫格,因为所处的列、行及九宫格 中,合计已出现过不同的8个数字,使得这个宫格所能填 入的数字,就只剩下那个还没出现过的数字时,我们称这 个宫格有唯余解。
唯一候选数法
所以如果在候选 数表中发现某一 个宫格的候选数 仅有1个数字,那 就是表示:不必 再考虑了!这个 宫格就是只能填 入这个数字啦
隐性唯一候选数法
利用「找出某一行、 某一列或某一个九宫 格各个宫格候选数中 只出现一次的数字来, 并将该数字填入出现 这个数字的宫格中」 的方法就叫做隐性唯 一候选数法(Hidden Singles Candidature, unique Candidate)。
编程实例
void preDo() {while(1) {setPb(); if(!fixAll()) break; if(isFull())//若已经推出全部结果 break;} //fixAll返回为假时也可能是推出了所有结果 if(isFull()) printAll();//打印结果}
(4)int stack[82];该数组的用途类似于栈,在核心回溯过程中起到至 关重要的作用。回溯之前,要把所有 fix数组中值为 0的位置依次存 放进stack数组;回溯中,由低到高依次逐渐确定这些位置的数值,无 法确定者(即 1-9的数字都不适合者)则应当回退到前一个位置,修改 其假设值,以此类推,直至 stack数组所存放的所有位置的值都能确 定,或回退到最初点的前一个位置。
唯一候選數法。(Singles Candidature, sole Candidate) 隱性唯一候選數法。(Hidden Singles Candidature,
unique Candidate) 區塊刪減法。(Locked Candidates, Single Sector
Candidates) 數對刪減法。(Naked Pairs) 隱性數對刪減法。(Hidden Pairs) 三鏈數刪減法。(Naked Triples) 隱性三鏈數刪減法。(Hidden Triples) 矩形頂點刪減法。(X-Wing) 三鏈列刪減法。(Swordfish) 關鍵數刪減法。(Colors, Colouring)
数独的算法—候选数法
因为规模不大 ,可以采用最易编写 ,可读性也很强的递归算法。即 当遇到无法找到唯一候选数的情况时 ,对所有可能解一次进行试探 , 若当前情况无解(填充函数返回值为假)时,进行回溯。整个递归过 程伪代码表示如下(递归过程命名为 work) :
过程 work(深度) 如果 深度大于 81 则 输出答案 否则 记录目前数表 如果 有唯一候选数 则如果 填充成功 则 work(深度 +1) 否则 依次遍历候选数 如果 填充成功 则 work(深度 +1)
数独的计算机求解
我们可以知道,直观法等以人的思维构建的方 法由计算机实现起来比较复杂,且效率不高。 所以,引入了候选数表,利用候选数法中的唯 一候选数法和隐性唯一候选数法,可以比较方 便的求解问题。
基于候选数法的可能求解算法
1分枝限界 2回溯
数独的算法—候选数法
如果在某一次填充之后 ,候选数表的某一位置只剩下 一个数 ,那么根据候选数表的定义 ,数盘的此位置一 定要填入这个数 ,这种解法称为“唯一候选数法”。
在实际编程中 ,可以用一个记录类型 ,其中包含两个 域:一个变量 t ,表示该格内可选数的个数 ,当 t=0 时就 找到了唯一解;另一个域为一个包含 9 个布尔型元素 的数组。当第i 个元素为真时就表示数字i 是可以被填 入此格的。经过这样的表示 ,每次尝试只需找到一个 t =0 的方格,再找到那个唯一可填的数 ,一次计算机模 拟的“唯一候选数法”就完成了。
void calculate() {preDo();//预处理以提高速度 if(isFull())return; int top=0; //将所有为 0的位置入栈 for(int i=1;i<82;i++) if(fix[i]==0) stack[top++]=i; int max=top;//记录最大数目加 1 top=0;//指向栈顶 int temp; bool flag=true; //该标志位说明了当前栈顶是正常进入的,还是经过了回退到的
电脑人工智慧已在现代任一项事物中均占有一席之地, 当然不会在数独这项最新流行的益智游戏中缺席了! 直观式的唯一解法及摒除法,不但在程式编写上也将 十分难以呈现,在执行效率上也将显得十分笨拙、于 是就有了候选数法的产生。
候选数表
将所有可能的值 填入对应的位置 的表。
最多9x9x9项
候选数法分类
这里的最小深度 63 和最多候选个数 2 是为了提高程序效率而设的阈值 ,根据实际情况的不同可以进行修改。
串行回溯法算法
设计程序的流程图
算法的数组定义
(1)int sd[82];该数组的用途是接收题目以及保存最终结果。所有的 9×9个数字被依次存储在该数组中,空白处则初始化为 0。
(2)int fix[82];该数组的用途是:若数组中某位置的数字不为0,则 数组fix相应位置的元素值记录为1,否则记录为0。即数组是用来记 录哪些位置的数字是已经确定下来的。
(3)bool型变量 flag初始化为 true。下面各步骤都将在一个条件始 终为真的死循环中进行,该循环由一条对 flag进行真假判断的 ifelse语句分成两大部分。flag所代表的意义是:若当前栈顶(top)是 经过了回退操作而达到的,则 flag会已被记录为假;否则flag为真。 死循环结束的条件是 top与 max的值相等,即解出最终结果,或者是 无解,最终 top小于 0(无解的情况基本上在最初做题目的合法性检 查时已经排除了)。在死循环中:若 flag为真,进入步骤(4),否则进入 步骤(5)。
数独算法的伪代码
过程 work(深度) 如果 深度大于 81 则 输出 答案 否则 记录目前数表 对数表排序 如果 有唯一候选数 则 如果 填充成功 则 work(深度 +1) 否则 取候选数最少的方格
如果 深度小于63 或 候选数 最少个数大于2 则 如果 有隐性唯一候选数 则 如果 填充成功 则 work(深 度 +1) 否则 依次遍历候选数 如果 填充成功 则 work(深 度 +1) 否则 回溯
数独问题及计算机求解
lscill
数独SuDoku
数独的由来 数独的经典算法 数独的计算机求解 数独的并行求解
什么是Sudoku??数独??
数独的由来
数独是一种源自18世纪末的瑞士,后在美 国发展、并在日本得以发扬光大的数学智力拼 图游戏。拼图是九宫格(即3格宽×3格高)的 正方形状,每一格又细分为一个九宫格。在每 一个小九宫格中,分别填上1至9的数字,让整 个大九宫格每一列、每一行的数字都不重复。
来自百度文库
数独的算法—候选数法
现在需要做的只是对这几种方法进行整合。
唯一候选数法”是最简便、最直接、最有效的 算法 ,因此 ,只要条件成立,就一定要用;搜索算 法具有一定的盲目性 ,但它的实现是无条件的 , 在经过优化后 ,其速度也不慢“;
隐性惟一候选数法”虽然直接 ,但由于其条件 判定较复杂 ,因此它可以作为减少搜索深度的 辅助算法。
数独的计算机算法
回溯法的基本思想下面给出详细的步骤与代码。
(1)按下标的由低到高扫描 fix数组,将值为 0的位置记录进stack数 组,记录的顺序也是由低到高。最后,整型量 max记录下:fix数组中 为 0位置的个数再加 1。
(2)整型量 top初始化为 0,即把 stack看作栈(虽然 stack数组的内 容永远不会变,但 top的增减仍代表了进栈和出栈的操作),top记录 的是栈顶。
(5)flag为假,说明是经过了回退才达到现在这个栈顶的,那么:若 仍然没有可能的数字可以应用在当前栈顶所保存的位置上,那么 继续执行出栈操作,即:fix数组和 sd数组的该位置重设为 0,top减 1;否则将遇到的第一个可能数字应用到该位置,即:再设好 sd数 组和 fix数组,将 top加 1,并将 flag置为真。本轮循环体结束,继续 下一轮的循环。
数独的计算机算法
(4)flag为真,说明栈顶(top)是经过正常的假设而达到的,并非由回 退达到,那么:根据 possible数组以及 beExist函数(参见 3.2节), 对栈顶所保存位置的可能出现的数字进行判断,把遇到的第一个 可能数字设置进 sd数组,并把 fix数组的该位置的值设为 1,并判 断是否已经解出结果,即 top和 max相等否,若相等,则打印结果 并退出死循环;若发现 1-9都不可能应用在栈顶所保存的位置,则 说明前面的假设有错误,此时应当回退,即:fix数组和 sd数组的该 位置重设为 0,top减 1,并将 flag置为假。本轮循环体结束,继续 下一轮的循环。
数独的由来
1783年,瑞士数学家莱昂哈德·欧拉发明了 一种当时称作“拉丁方块”的游戏,这个游 戏是一个n×n的数字方阵,每一行和每一列 都是由不重复的n个数字或者字母组成的。
用从1开始的n个连续正整数排成n行n列的方 阵,如果每一行和每一列都没有重复的数, 就称为一个n阶拉丁方。因为这样的方阵最早 填充的是拉丁字母,故名。 下面是一个3阶拉丁方
使用直观法时,大部分的时间 应该都在使用基础摒除法,但
有些较困难的数独题目,不时 会出现以基础摒除法将找不到 解的情况,这时就是唯余解法 上场应用的机会
数独的算法—候选数法
数独的解谜技巧,刚开始发展时,以直观式的唯一解 法及摒除法为主,对于一般简易级或中级的数独谜题, 通常已游刃有余。 但是唯一解法及初阶的摒除法在使 用上有其限制,在中、高级的题目中有时将无用武之 地。但高阶的摒除技巧又十分繁难。
基础摒除法>> 唯一解法。 区块摒除法。 唯余解法。 单元摒除法。 矩形摒除法。 余数测试法。
基础摒除法
基础摒除法虽然简单,但在实际应用时,仍然可 分成三个部分:
行摒除:因为同一行不能有两个相同的数字,所以当 某个数字已在某行中出现时,该行再填入该数字的可能性 就应该被摒除掉。
列摒除:因为同一列不能有两个相同的数字,所以当 某个数字已在某列中出现时,该列再填入该数字的可能性 就应该被摒除掉。
(3)int possible[82][10];该数组的用途是记录所有未确定数字的所有 可能性 记录方法是 数组各元素的值在初始化时被初始化为与其第 二维的下标一致 即 0-9;中间计算过程中,若发现第一维某位置的某 种可能性已不复存在 则将第一维下标是该位置而第二维下标是该 不再可能的数字的元素值改为-1。
否则 回溯
数独的算法—候选数法
当候选数表的某一个区域(行、列或九宫格)中 某一个数字只存在于一个格中 ,那么那个数字 必应填入此格。这是因为本数字必须出现在这 一区域 ,进而只能出现在这一格中 ,这种解法称 为“隐性唯一候选数法”。
每次尝试只需找到一个使 N[i ,x] = 1 的 i 和 x 表示的区域 ,再找到那个区域中可填入i 的方 格 ,一次计算机模拟的“隐性唯一候选数法” 就完成了。
123 231 312
数独的问题
拉丁方不一定是数独的解 数独问题不可由数学公式推算
数独的人工算法
直观法&摒除法 候选数法 不动点法
数独的算法—直观法
直观法的特性: 不需任何辅助工具就可应用。所以要玩报
章杂志上的数独谜题时,只要有一枝笔就可 以开始了.
数独的算法—直观法
直觀法的主要的技巧:
数独的由来
数独前身为“九宫格”,最早起源于中国。 数千年前,我们的祖先就发明了洛书,其特 点较之现在的数独更为复杂,要求纵向、横 向、斜向上的三个数字之和等于15,而非简 单的九个数字不能重复。儒家典籍《易经》 中的“九宫图”也源于此,故称“洛书九宫 图”。而“九宫”之名也因《易经》在中华 文化发展史上的重要地位而保存、沿用至今。
宫摒除:因为同一个九宫格不能有两个相同的数字, 所以当某个数字已在某个九宫格中出现时,该九宫格再填 入该数字的可能性就应该被摒除掉。
唯一解法
唯余解
当数独谜题中的某一个宫格,因为所处的列、行及九宫格 中,合计已出现过不同的8个数字,使得这个宫格所能填 入的数字,就只剩下那个还没出现过的数字时,我们称这 个宫格有唯余解。
唯一候选数法
所以如果在候选 数表中发现某一 个宫格的候选数 仅有1个数字,那 就是表示:不必 再考虑了!这个 宫格就是只能填 入这个数字啦
隐性唯一候选数法
利用「找出某一行、 某一列或某一个九宫 格各个宫格候选数中 只出现一次的数字来, 并将该数字填入出现 这个数字的宫格中」 的方法就叫做隐性唯 一候选数法(Hidden Singles Candidature, unique Candidate)。
编程实例
void preDo() {while(1) {setPb(); if(!fixAll()) break; if(isFull())//若已经推出全部结果 break;} //fixAll返回为假时也可能是推出了所有结果 if(isFull()) printAll();//打印结果}
(4)int stack[82];该数组的用途类似于栈,在核心回溯过程中起到至 关重要的作用。回溯之前,要把所有 fix数组中值为 0的位置依次存 放进stack数组;回溯中,由低到高依次逐渐确定这些位置的数值,无 法确定者(即 1-9的数字都不适合者)则应当回退到前一个位置,修改 其假设值,以此类推,直至 stack数组所存放的所有位置的值都能确 定,或回退到最初点的前一个位置。
唯一候選數法。(Singles Candidature, sole Candidate) 隱性唯一候選數法。(Hidden Singles Candidature,
unique Candidate) 區塊刪減法。(Locked Candidates, Single Sector
Candidates) 數對刪減法。(Naked Pairs) 隱性數對刪減法。(Hidden Pairs) 三鏈數刪減法。(Naked Triples) 隱性三鏈數刪減法。(Hidden Triples) 矩形頂點刪減法。(X-Wing) 三鏈列刪減法。(Swordfish) 關鍵數刪減法。(Colors, Colouring)
数独的算法—候选数法
因为规模不大 ,可以采用最易编写 ,可读性也很强的递归算法。即 当遇到无法找到唯一候选数的情况时 ,对所有可能解一次进行试探 , 若当前情况无解(填充函数返回值为假)时,进行回溯。整个递归过 程伪代码表示如下(递归过程命名为 work) :
过程 work(深度) 如果 深度大于 81 则 输出答案 否则 记录目前数表 如果 有唯一候选数 则如果 填充成功 则 work(深度 +1) 否则 依次遍历候选数 如果 填充成功 则 work(深度 +1)
数独的计算机求解
我们可以知道,直观法等以人的思维构建的方 法由计算机实现起来比较复杂,且效率不高。 所以,引入了候选数表,利用候选数法中的唯 一候选数法和隐性唯一候选数法,可以比较方 便的求解问题。
基于候选数法的可能求解算法
1分枝限界 2回溯
数独的算法—候选数法
如果在某一次填充之后 ,候选数表的某一位置只剩下 一个数 ,那么根据候选数表的定义 ,数盘的此位置一 定要填入这个数 ,这种解法称为“唯一候选数法”。
在实际编程中 ,可以用一个记录类型 ,其中包含两个 域:一个变量 t ,表示该格内可选数的个数 ,当 t=0 时就 找到了唯一解;另一个域为一个包含 9 个布尔型元素 的数组。当第i 个元素为真时就表示数字i 是可以被填 入此格的。经过这样的表示 ,每次尝试只需找到一个 t =0 的方格,再找到那个唯一可填的数 ,一次计算机模 拟的“唯一候选数法”就完成了。
void calculate() {preDo();//预处理以提高速度 if(isFull())return; int top=0; //将所有为 0的位置入栈 for(int i=1;i<82;i++) if(fix[i]==0) stack[top++]=i; int max=top;//记录最大数目加 1 top=0;//指向栈顶 int temp; bool flag=true; //该标志位说明了当前栈顶是正常进入的,还是经过了回退到的
电脑人工智慧已在现代任一项事物中均占有一席之地, 当然不会在数独这项最新流行的益智游戏中缺席了! 直观式的唯一解法及摒除法,不但在程式编写上也将 十分难以呈现,在执行效率上也将显得十分笨拙、于 是就有了候选数法的产生。
候选数表
将所有可能的值 填入对应的位置 的表。
最多9x9x9项
候选数法分类
这里的最小深度 63 和最多候选个数 2 是为了提高程序效率而设的阈值 ,根据实际情况的不同可以进行修改。
串行回溯法算法
设计程序的流程图
算法的数组定义
(1)int sd[82];该数组的用途是接收题目以及保存最终结果。所有的 9×9个数字被依次存储在该数组中,空白处则初始化为 0。
(2)int fix[82];该数组的用途是:若数组中某位置的数字不为0,则 数组fix相应位置的元素值记录为1,否则记录为0。即数组是用来记 录哪些位置的数字是已经确定下来的。
(3)bool型变量 flag初始化为 true。下面各步骤都将在一个条件始 终为真的死循环中进行,该循环由一条对 flag进行真假判断的 ifelse语句分成两大部分。flag所代表的意义是:若当前栈顶(top)是 经过了回退操作而达到的,则 flag会已被记录为假;否则flag为真。 死循环结束的条件是 top与 max的值相等,即解出最终结果,或者是 无解,最终 top小于 0(无解的情况基本上在最初做题目的合法性检 查时已经排除了)。在死循环中:若 flag为真,进入步骤(4),否则进入 步骤(5)。
数独算法的伪代码
过程 work(深度) 如果 深度大于 81 则 输出 答案 否则 记录目前数表 对数表排序 如果 有唯一候选数 则 如果 填充成功 则 work(深度 +1) 否则 取候选数最少的方格
如果 深度小于63 或 候选数 最少个数大于2 则 如果 有隐性唯一候选数 则 如果 填充成功 则 work(深 度 +1) 否则 依次遍历候选数 如果 填充成功 则 work(深 度 +1) 否则 回溯