当前位置:首页 > 数码 > 经常使用C-解密数独的算法之美-成功数独求解器 (经常使用CAD买什么电脑)

经常使用C-解密数独的算法之美-成功数独求解器 (经常使用CAD买什么电脑)

admin4个月前 (05-07)数码30

引言:

数独是一种经典的逻辑推理游戏,经过填充9x9方格中的数字,使得每一行、每一列和每一个3x3的小方格内都蕴含了1到9的数字,且不重复。本文将引见如何经常使用C++编写一个数独求解器,经过算法成功智能处置数独难题的配置。
一、疑问剖析
数独求解疑问可以看作是一个经典的递归回溯疑问。咱们须要设计一个算法,能够在填充数字的环节中遵照数独规定,并经过试错的模式处置数独难题。
二、算法成功
数独数据结构定义
咱们可以经常使用一个二维数组来示意数独的初始形态和处置形态。定义一个9x9的整型数组board,其中0示意未填充的格子。
intboard[9][9]={{5,3,0,0,7,0,0,0,0},{6,0,0,1,9,5,0,0,0},{0,9,8,0,0,0,0,6,0},{8,0,0,0,6,0,0,0,3},{4,0,0,8,0,3,0,0,1},{7,0,0,0,2,0,0,0,6},{0,6,0,0,0,0,2,8,0},{0,0,0,4,1,9,0,0,5},{0,0,0,0,8,0,0,7,9}};
回溯算法成功
经过递归回溯算法,咱们可以遍历数独中的每一个未填充的格子,尝试填充1到9的数字,并逐渐验证能否满足数独的规定。
boolsolveSudoku(introw,intcol){if(row==9){//数独已处置returntrue;}if(col==9){//以后行已填充终了,进入下一行returnsolveSudoku(row+1,0);}if(board[row][col]!=0){//以后格子已填充数字,进入下一列returnsolveSudoku(row,col+1);}for(intnum=1;num<=9;num++){if(isValid(row,col,num)){//填充数字并进入下一列board[row][col]=num;if(solveSudoku(row,col+1)){returntrue;}//回溯,尝试其余数字board[row][col]=0;}}returnfalse;}
验证数独规定
在回溯算法中,咱们须要编写验证函数isValid,用于判别填充的数字能否满足数独的规定。
boolisValid(introw,intcol,intnum){//判别以后数字能否已存在于同一行或同一列for(inti=0;i<9;i++){if(board[row][i]==num||board[i][col]==num){returnfalse;}}//判别以后数字能否已存在于同一个3x3的小方格内intstartRow=(row/3)*3;intstartCol=(col/3)*3;for(inti=startRow;i<startRow+3;i++){for(intj=startCol;j<startCol+3;j++){if(board[i][j]==num){returnfalse;}}}returntrue;}
完整求解器成功
将上述代码整合起来,咱们可以获取一个完整的数独求解器。
#include<tream>usingnamespacestd;intboard[9][9]={{5,3,0,0,7,0,0,0,0},{6,0,0,1,9,5,0,0,0},{0,9,8,0,0,0,0,6,0},{8,0,0,0,6,0,0,0,3},{4,0,0,8,0,3,0,0,1},{7,0,0,0,2,0,0,0,6},{0,6,0,0,0,0,2,8,0},{0,0,0,4,1,9,0,0,5},{0,0,0,0,8,0,0,7,9}};boolisValid(introw,intcol,intnum){//判别以后数字能否已存在于同一行或同一列for(inti=0;i<9;i++){if(board[row][i]==num||board[i][col]==num){returnfalse;}}//判别以后数字能否已存在于同一个3x3的小方格内intstartRow=(row/3)*3;intstartCol=(col/3)*3;for(inti=startRow;i<startRow+3;i++){for(intj=startCol;j<startCol+3;j++){if(board[i][j]==num){returnfalse;}}}returntrue;}boolsolveSudoku(introw,intcol){if(row==9){//数独已处置returntrue;}if(col==9){//以后行已填充终了,进入下一行returnsolveSudoku(row+1,0);}if(board[row][col]!=0){//以后格子已填充数字,进入下一列returnsolveSudoku(row,col+1);}for(intnum=1;num<=9;num++){if(isValid(row,col,num)){//填充数字并进入下一列board[row][col]=num;if(solveSudoku(row,col+1)){returntrue;}//回溯,尝试其余数字board[row][col]=0;}}returnfalse;}voidprintBoard(){for(inti=0;i<9;i++){for(intj=0;j<9;j++){cout<<board[i][j]<<"";}cout<<endl;}}intmn(){if(solveSudoku(0,0)){cout<<"数独已处置:"<<endl;printBoard();}else{cout<<"数独无解"<<endl;}return0;}
三、算法剖析与优化
复杂度剖析
数独求解器的期间复杂度取决于回溯的次数,最坏状况下须要尝试9的81次方次操作,但在实践运行中,因为数独疑问的不凡性,通常可以在较少的回溯步骤内处置。
算法优化
为了提高数独求解器的效率,咱们可以思考以下优化措施:
C 启示式搜查: 在回溯算法中经常使用启示式搜查战略,选用填充数字时优先选用或者性最小的格子,以缩小回溯的次数。
剪枝操作: 在验证数独规定时,可以经常使用剪枝操作,缩小不用要的验证环节。例如,可以经常使用位运算来极速判别某一行、某一列或某一小方格内能否已存在某个数字。
五、总结
本文引见了如何经常使用C++编写一个数独求解器,经过回溯算法成功智能处置数独难题的配置。咱们讨论了算法的成功细节,并提出了一些优化措施以提高求解器的效率。数独求解器是一个典型的递归回溯疑问,经过深化了解数独规定和正当设计算法,咱们能够处置各种难度的数独疑问。

基础摒除法数独技巧基础摒除法就是利用1~9的数字在每一行、每一列、每一个九宫格都只能出现一次的规则进行解题的方法。 基础摒除法可以分为行摒除、列摒除、九宫格摒除。 实际寻找解的过程为: 寻找九宫格摒除解:找到了某数在某一个九宫格可填入的位置只余一个的情形;意即找到了该数在该九宫格中的填入位置。 寻找列摒除解:找到了某数在某列可填入的位置只余一个的情形;意即找到了该数在该列中的填入位置。 寻找行摒除解:找到了某数在某行可填入的位置只余一个的情形;意即找到了该数在该行中的填入位置。 看能用基础摒除法确定B2、C8、E7、F6、I5的数字吗? 数独A4=9,则A行其它格排除9,G1=9,第1列排除数字9,D3=9,第3列排除数字9。 由基础摒除法,第A1所在的九宫格内9只有一个唯一的位置,即确定B2=9。 A4=9,则4列其它格排除9,G1=9,第G行排除数字9,H9=9,第H行排除数字9。 数独由基础摒除法,第G4所在的九宫格内9只有一个唯一的位置,即确定I5=9。 A4=9,则4列其它格排除9,D3=9,第D行排除数字9,I5=9,第5列排除数字9。 由基础摒除法,第D4所在的九宫格内9只有一个唯一的位置,即确定F6=9。 数独A4=9,则A行其它格排除9,B2=9,第B行排除数字9,H9=9,第9列排除数字9。 由基础摒除法,第A7所在的九宫格内9只有一个唯一的位置,即确定C8=9。 C8=9,则8列其它格排除9,D3=9,第D行排除数字9,F6=9,第F行排除数字9,H9=9,第9列排除数字9。 由基础摒除法,第D7所在的九宫格内9只有一个唯一的位置,即确定E7=9。 编辑本段唯一解法当某行已填数字的宫格达到8个,那么该行剩余宫格能填的数字就只剩下那个还没出现过的数字了。 成为行唯一解。 编辑本段唯余解法唯余解法就是某宫格可以添入的数已经排除了8个,那么这个宫格的数字就只能添入那个没有出现的数字。 数独A5=?,其实这就是唯余解法的原理,很简单,但是实际使用时就不会容易发现了。 数独能使用唯余解法确定B7的值吗? 能确定E9,A9,B9,C9的值吗? 由区块摒除法可以得出E9=9。 数独技巧数独技巧由唯余解法,C9=2。 同样,可以得到其他。 编辑本段区块摒除法数独技巧区块摒除法是基础摒除法的提升方法,是直观法中使用频率最高的方法之一。 所谓区块,就是将行分成3个三个相连的小方块构成,列也是分成3个三个相连的小方块构成.九宫格同样被看成由3个三个相连的小方块构成,如下面示意图:数独区块摒除法的核心思想如下面解释(以行为例),对于在列也是相同的道理。 假如(G1~G3)黄色区域区块其中之一是数字9。 数独则,(H4~H6)蓝色区域可能含有数字9,否则(I4~I6)绿色区域含有数字9。 假定我们已确定(G1~G3)黄色区域区块其中之一是数字9,(H4~H6)蓝色区域不含有数字9,则:在(I7~I9)绿色区域一定含有数字9.如果再通过其它方法确定(I7~I9)绿色区域中某两个宫格不能为数字9,则就能确定数字9在(I7~I9)区块的具体位置。 编辑本段余数测试法所谓余数测试法就是在某行或列,九宫格所填数字比较多,剩余2个或3个时,在剩余宫格添入值进行测试的解题方法。 数独技巧在B行,C行剩余未填的数字只有两三个了,这时可以使用余数测试法进行解题。 我们看B行,B3可能添入的数为5或者6,我们从5开始测试 我们在B3添入5进行测试,得到左图,没有得出出错的推断,所以B3=5可能是正确的判断,如果能判断出B3不能添6,则才能肯定B3=5。 所以下面我们还需要用B3=6进行测试。 在B3添入6,推出A1=5.观察A5,A6,必含数字5,证明B3=6是错误的.从而得出B3=5。 编辑本段唯一候选数法数独技巧候选数法解题的过程就是逐渐排除不合适的候选数的过程,当某个宫格的候选数排除到只有一个数的时候,那么这个数就是该宫格的唯一的一个候选数,这个候选数就可以解了。 隐性唯一候选数法 当某个数字在某一列各宫格的候选数中只出现一次时,那么这个数字就是这一列的唯一候选数了.这个宫格的值就可以确定为该数字.这时因为,按照数独游戏的规则要求每一列都应该包含数字1~9,而其它宫格的候选数都不含有该数,则该数不可能出现在其它的宫格,那么就只能出现在这个宫格了.对于唯一候选数出现行,九宫格的情况,处理方法完全相同。 数独技巧这是制作好的一张候选数表,注意观察B5,B9,D1。 可以看出在第1列,数字9只在D1出现。 在第5列,数字3只在B5出现。 在B9所处的九宫格里,数字9只有在B9出现。 所以9是第1列的隐形唯一候选数,3是第5列的隐形唯一候选数,9是A7九宫格的隐形唯一候选数。 [1]编辑本段三链数删减法找出某一列、某一行或某一个九宫格中的某三个宫格候选数中,相异的数字不超过3个的情形,进而将这3个数字自其它宫格的候选数中删减掉的方法就叫做三链数删减法。 隐性三链数删减法:在某行,存在三个数字出现在相同的宫格内,在本行的其它宫格均不包含这三个数字,我们称这个数对是隐形三链数.那么这三个宫格的候选数中的其它数字都可以排除.当隐形三链数出现在列,九宫格,处理方法是完全相同的.矩形顶点删减法,矩形顶点删减法和直观法讲到的矩形摒除法分析方法是一样的。 矩形顶点删减法在识别时比较不容易找到,所以最好先使用其它的方法。 三链数删减法的原理如下面图示: 在H行,H2,H5,H7的候选数(12),(23),(13),构成三链数,那么123这三个数在H行将只能出现在H2,H5,H7,那么本行其它宫格就可以删除这3个候选数了。 这是三链数发生在行的情况。 在G7所在九宫格,G7,H8,I9的候选数(12),(23),(13),构成三链数,那么123这三个数在这个九宫格将只能出现在G7,H8,I9,那么本九宫格其它宫格就可以删除这3个候选数了。 这是三链数发生在九宫格的情况。 三链数是数对的扩展,我们在对上面的三链数进行扩展,得到右边的特殊的三链数,只要保证在3个宫格内,其包含的候选数也为3个,就都符合我们的要求,比如(123,123,123),(12,123,123)或(12,23,123)都符合要求。 我们进一步再扩充,发现只要在N个宫格内,其包含的候选数也恰为N个,那么处理和三链数是相同的道理,这样就形成了四链数,比如(12,23,34,14),(123,123,14,1234)等。 甚至可以扩充到五链数,七链数(虽然在实际解题中作用不大了)。 平时我们用到最多的就是三链数,四链数了。 在A4所在九宫格,我们看到B4~B6,形成三链数,则本九宫格其它宫格就可以去除候选数2,7,9,这样就得到C6=4。 同上面完全相同的一副图,在A行,A7~A9形成由179构成的三链数,排除本行其它宫格的候选数179后得到A3=3。 编辑本段三链列删减法三链列删减法是矩形顶点删减法的扩展,如果不清楚矩形顶点删减法,可以参考矩形顶点删减法,以便于更容易理解本节内容。 利用“找出某个数字在某三列仅出现在相同三行的情形,进而将该数字自这三行其他宫格候选数中删减掉”;或“找出某个数字在某三行仅出现在相同三列的情形,进而将该数字自这三列其他宫格候选数中删减掉”的方法就叫做三链列删减法。 关键数删减法 在进入到解题后期,利用前面讲到的唯一候选数法、隐性唯一候选数法、区块删减法、数对删减法、隐性数对删减法、三链数删减法、隐性三链数删减法、矩形顶点删减法、三链列删减法都无法有进展的时候,可以考虑使用关键数删减法。 关键数删减法就是在后期找到一个数,这个数在行(或列,九宫格)仅出现两次的数字。 我们假定这个数在其中一个宫格类,继续求解,如果发生错误,则确定我们的假设错误。 如果继续求解仍然出现困难,不妨假设这个数在另外一个宫格,看能不能得到错误。 这就是关键数删减法。 如果数字“1”可能出现在B行、E行、G行的黄色宫格,则符合“某个数字在某三列仅出现在相同三行的情形”,符合三链列删减法的要求。 则红色宫格均不包含候选数“1”。 这时上图的一个变形。 其中一行的“1”只能放在这一行的两个位置。 处理和上图一样,红色宫格均可以排除候选数“1”。 数字6在第2列,第6列,第8列。 均出现在A,B,I行。 其中在第6列仅出现B,I行,仍然符合三链列删减法的要求。 编辑本段直观法解题技巧数独直观法解题技巧主要有 单元限定法、单元排除法、区块排除法、唯一余解法、矩形排除法、逐行逐列依次扫描法、综合扫描法、唯一候选数法、隐性唯一候选数法、 区块删减法、数对删减法、隐性数对删减法、三链数删减法、隐性三链数删减法、矩形顶点删减法、三链列删减法、关键数删减法、关连数删减法。 1.联除法。 在并排的三个九宫格中的两排寻找相同数字,再利用九宫格得出另一排中该数字位置,该方法适用于中高级数独. 2.巡格法 找出在每个九宫格中出现频率较高的数字,得出该数字在其余九宫格内位置,该方法应用于方法一之后。 3.排除法 这个方法是解决问题的关键,易被常人所忽略。 在各行列或九宫格中观察,若有个位置其它数字都不能填,就填余下的数字 4.待定法 此方法不常用却很有效。 暂时确定某个数字在某个区域,再利用其来进行排除 5.行列法 此方法用于收官阶段,利用先从行列突破来提高解题效率。 6.假设法 作为一名高手,我不提倡这种方法。 即在某个位置随机的填上一个数字,再进行推演,并有可能最终产生矛盾而否定结论. 7.频率法 这种方法相比于上一种方法更能提高效率。 在某一行列或九宫格列举出所有情况,再选择某位置中出现频率高的数字 8.候选数法 使用候选数法解数独题目需先建立候选数列表,根据各种条件,逐步安全的清除每个宫格候选数的不可能取值的候选数,从而达到解题的目的。 使用候选数法一般能解比较复杂的数独题目,但是候选数法的使用没有直观法那么直接,需要先建立一个候选数列表的准备过程,所以实际使用时可以先利用直观法进行解题,到无法用直观法解题时再使用候选数法解题。 候选数法解题的过程就是逐渐排除不合适的候选数的过程,所以在进行候选数删除的时候一定要小心,确定安全地删除不合适的候选数,否则,很多时候只有重新做题了。 有了计算机软件的帮助,使得候选数表的维护变得轻松起来。

免责声明:本文转载或采集自网络,版权归原作者所有。本网站刊发此文旨在传递更多信息,并不代表本网赞同其观点和对其真实性负责。如涉及版权、内容等问题,请联系本网,我们将在第一时间删除。同时,本网站不对所刊发内容的准确性、真实性、完整性、及时性、原创性等进行保证,请读者仅作参考,并请自行核实相关内容。对于因使用或依赖本文内容所产生的任何直接或间接损失,本网站不承担任何责任。

标签: C

“经常使用C-解密数独的算法之美-成功数独求解器 (经常使用CAD买什么电脑)” 的相关文章

编程实践-哈希负载均衡算法-IP-C (编程实践心得体会)

编程实践-哈希负载均衡算法-IP-C (编程实践心得体会)

Nginx 是一个高性能的开源 Web 服务器和反向代理服务器,因其高效处理高并发的请求而闻名。以下是一些 Nginx 用于处理高并发的主要特点和技术: 事件驱动架构: Nginx 使...

深化探求模板编程的精华-从类型参数到智能推导-模板的艺术-C-把握 (深化探求模板范文)

深化探求模板编程的精华-从类型参数到智能推导-模板的艺术-C-把握 (深化探求模板范文)

类型模板参数 在示例中,模板有一个模板参数:存储在网格中的类型。编写类模板时,您须要在尖括号内指定参数列表,例如: 这个参数列表相似于函数或方法中的参数列表。与函数和...

揭秘性能与并发的机密-C-多线程编程 (性能与什么有关)

揭秘性能与并发的机密-C-多线程编程 (性能与什么有关)

当天咱们将深化讨论C++中的多线程编程,提醒多线程如何解锁性能后劲,提高程序的并发性能。 什么是多线程? 在计算机迷信中,多线程是指一个进程(程序的口头实例)中的多个线程同时口头。每个...

提升性能的新利器-17中的并行功能-C (提升 性能)

提升性能的新利器-17中的并行功能-C (提升 性能)

C++17扩展了STL(Standard Template Library,标准模板库)以支持并行算法。这意味着许多常见的算法,如std::sort、std::for_each、std::tran...

开源项目-助初学者进阶成长-C-八个 (开源项目有什么用)

开源项目-助初学者进阶成长-C-八个 (开源项目有什么用)

通过参与或阅读开源项目的源代码,你可以获得丰富的实践机会。实际的项目代码比简单的教程更具挑战性,可以帮助你深入理解 C++ 的各种概念和技术。 ThreadPool 一个简单...

让新手也能轻松把握-C-类模板特化与承袭经常使用指南 (请问新手)

让新手也能轻松把握-C-类模板特化与承袭经常使用指南 (请问新手)

一、类模板特化 1.特化的成功 你可以为特定类型提供类模板的替代成功。例如,你或许以为constchar类型(C格调字符串)的Grid行为没无心义。Grid<constchar&...

了解圈套和无效经常使用技巧-言语变长参数-C (了解圈套和无线的区别)

了解圈套和无效经常使用技巧-言语变长参数-C (了解圈套和无线的区别)

C工具 变长参数列表 这局部解释了旧的C格调变长参数列表。了解这些内容很关键,由于你或许会在遗留代码中遇到它们。但是,在新代码中,你应该经常使用变参模板来成功类型安保的变长参数列表。...

的区别-中-C-math.h-和-cmath (的区别中的钱)

的区别-中-C-math.h-和-cmath (的区别中的钱)

一、引言 C++规范库中的<cmath>和C言语规范库中的<math.h>均为数学函数库,它们提供了一系列数学函数和常量。但是,这两者之间存在一些关键的区别...