回溯法是剪了枝的穷举,这是字面上的说法,不太好理解,不如讲解实例来的酸爽,于是引出了N阶可达问题:

  有N个国家,每个国家有若干城市,小明要从中国(任意一个城市)出发,遍历所有国家(假设这个遍历顺序已经定了),最终到达美利坚(任意一个城市)。而城市之间有可能不可达,只有小明尝试过才知道(就是后面的check()函数),求满足要求的一条路径?

  从上面的表述中我们已经嗅到了浓浓的穷举屌丝气质——遍历所有组合,但是我们的回溯思想总是基于这样一个简单的事实:如果当前选择导致你走进了死胡同,那么这个选择一定是错误的,同时基于这个错误的后续所有的选择都是错误而无意义的(剪枝)。道理的前半句表明我们要及时回溯,而后半句指出了这样做的优点是剪枝。比如小明要遍历中国---日本---美国,小明选择从中国武汉出发,这个选择是正确的还是错误的尚不明确,但是小明经过许多个check()之后发现,没有从武汉到日本任意一个城市的可达线路,这说明选择从武汉出发这个决定是错误的,应该回溯,重新选择一个中国的起点城市,小明在不知不觉中已经排除了形如(中国武汉市)---(日本XX市)---(美国XX市)的诸多组合,这就是所谓的剪了枝的穷举。

  数独问题也是典型的N阶可达问题,下面以一个挖去64个洞的数独为例来具体说明,每个洞有1~9共9种可能性,一共要填64个洞,并且每填写好一个洞对后续的步骤会产生影响。

  假设我们是从左到右,从上到下依次填写数字,那么此数独问题可以表达为如下的64阶可达问题:

  根据回溯思想,采用递归函数(因为每层的情况是一样的,请读者思考如果不一样该如何编程)依次处理编号为0~80共计81个格子(代码略)。

  下面我们用号称世界最难的数独题来测试一下程序,首先在程序同目录下建立sudoku.txt的文件,然后输入以下内容:

800000000
003600000
070090200
050007000
000045700
000100030
001000068
008500010
090000400

  保存然后运行程序,得到如下结果。程序大约运行了60ms,在进行了49584次尝试之后找到了数独的解。

  再来一发,号称专杀暴力破解的数独题试一下:

  哇,好奇怪,世界最难数独都能在百毫秒内求解,为什么这个数独题居然花了大约37秒?莫非此数独真的有专杀暴力破解的神秘力量?前面我们说回溯只是做了剪枝的工作,下面这幅图展示了回溯到底做了什么:

剪枝后只用搜索红色部分

  从本质上说,搜索是一维的,答案位于这个一维地图中的某处,你搜索速度的快慢取决于你的地图和答案在地图中的位置。前面我们尝试的顺序是123456789,现在我们尝试987654321这个搜索顺序,把程序修改一番,再次运行哪个两个数独,结果如下:

左为世界最难,右边为专杀暴力

  上面我们只是改变了搜索顺序,只是一维地图的反转后搜索,相当于地图没变我们换了另一头搜索。在第一程序中,之所以很快能搜索到世界最难数独,而搜索专杀爆破很慢,是因为世界最难的答案离这一端很近,专杀爆破的答案离这一端很远。当我们在不改变地图的情况下换另一端开始搜索,就会出现上面的结果。

  故在数独算法中,每个人都说自己的算法是高效的,并给出试验数据。实际上这个说法并不准确,只能说采用不同的方法,地图的规模不同,答案所在的位置也不同。对于同一个数独,你的算法你别人快并不能说明什么,因为必然存在专杀你这种搜索方法的数独存在。你的算法搜索的越快,换个姿势一定就会越慢。

回溯法、数独与N阶可达问题的更多相关文章

  1. P1074 靶形数独 dfs回溯法

    题目描述 小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他们想用数独来一比高低.但普通的数独对他们来说都过于简单了,于是他们向 Z 博士请教,Z 博士拿出了他最近发明的“靶 ...

  2. Leetcode之回溯法专题-37. 解数独(Sudoku Solver)

    Leetcode之回溯法专题-37. 解数独(Sudoku Solver) 编写一个程序,通过已填充的空格来解决数独问题. 一个数独的解法需遵循如下规则: 数字 1-9 在每一行只能出现一次.数字 1 ...

  3. python常用算法(7)——动态规划,回溯法

    引言:从斐波那契数列看动态规划 斐波那契数列:Fn = Fn-1 + Fn-2    ( n = 1,2     fib(1) = fib(2) = 1) 练习:使用递归和非递归的方法来求解斐波那契数 ...

  4. N-Queens And N-Queens II [LeetCode] + Generate Parentheses[LeetCode] + 回溯法

    回溯法 百度百科:回溯法(探索与回溯法)是一种选优搜索法,按选优条件向前搜索,以达到目标.但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步又一次选择,这样的走不通就退回再走的技术为回溯法 ...

  5. 从Leetcode的Combination Sum系列谈起回溯法

    在LeetCode上面有一组非常经典的题型--Combination Sum,从1到4.其实就是类似于给定一个数组和一个整数,然后求数组里面哪几个数的组合相加结果为给定的整数.在这个题型系列中,1.2 ...

  6. 五大常用算法之四:回溯法[zz]

    http://www.cnblogs.com/steven_oyj/archive/2010/05/22/1741376.html 1.概念 回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试 ...

  7. 算法入门经典-第七章 例题7-4-1 拓展 n皇后问题 回溯法

    实际上回溯法有暴力破解的意思在里面,解决一个问题,一路走到底,路无法通,返回寻找另   一条路. 回溯法可以解决很多的问题,如:N皇后问题和迷宫问题. 一.概念 回溯算法实际类似枚举的搜索尝试过程,主 ...

  8. 0-1背包问题——回溯法求解【Python】

    回溯法求解0-1背包问题: 问题:背包大小 w,物品个数 n,每个物品的重量与价值分别对应 w[i] 与 v[i],求放入背包中物品的总价值最大. 回溯法核心:能进则进,进不了则换,换不了则退.(按照 ...

  9. 【LeetCode】回溯法 backtracking(共39题)

    [10]Regular Expression Matching [17]Letter Combinations of a Phone Number [22]Generate Parentheses ( ...

随机推荐

  1. Java 之复合赋值运算符

    1.引入问题 切入正题,看下面代码,结果应该是怎么样的 public class App{ public static void main( String[] args ){ byte a=1 ; i ...

  2. weblogic启动报错--com.octetstring.vde.backend.BackendRoot

    错误现象: 使用bea用户启动weblogic时报错,错误信息如下: <2014-7-29 下午07时47分23秒 CST> <Notice> <Log Manageme ...

  3. 造出最好的 CMS 轮子

    zerojs! 造出最好的 CMS 轮子 zerojs是一个基于nodejs.angularjs.git的CMS.在它之上可以继续开发出博客.论坛.wiki等类似的内容管理型系统. 拥抱开发者和社区 ...

  4. [转]JavaScript Namespaces and Modules

    Namespaces In most programming languages we know the concept of namespaces (or packages).Namespaces ...

  5. Eclipse编辑器样式修改

    很多的开发工具都可以更改主题样式,但eclipse作为一款影响力巨大的开源开发工具,却没有自带更改样式的功能,这多少令人有点小遗憾.Eclipse 4之后,Eclipse使用者呼声高涨,就有人开始做起 ...

  6. ASP.NET WebApi 增删改查

    本篇是接着上一篇<ASP.NET WebApi 入门>来介绍的. 前言 习惯说 CRUD操作,它的意思是"创建. 读取. 更新和删除"四个基本的数据库操作.许多 HTT ...

  7. C#多线程--仓库问题引发的故事

    假设有这么个场景,一个仓库,里面有N件货物,现有六个搬运工(用线程模拟),其中2个向仓库放东西,4个往外搬东西.假设1秒能向里放2件货物,同时可向外搬3件货物(线程休眠),现在需要往里放M件货物,一旦 ...

  8. 安装升级System.Web.Optimization.dll

    今天在使用backload时,VS提示solution所引用的System.Web.Optimization.dll 版本低,编译不过,于是便删掉,从新添加引用,悲剧的是在添加引用窗口中没找到,在Nu ...

  9. 解决android studiogradle 错误 找不到程序包 符号

    问题:android studio gradle 错误 找不到程序包 符号解决:原因是library工程的build.gradle含有release,只要把其注释即可 buildTypes { rel ...

  10. MySQL关联查询总结

    MySQL中经常使用关联查询,有机会总结下: 1 left join(左联查询): 返回包括左表中的所有记录和右表中联接字段相等的记录 例:select * from a left join b on ...