DFS中的奇偶剪枝学习笔记

奇偶剪枝学习笔记

描述

编辑

现假设起点为(sx,sy),终点为(ex,ey),给定t步恰好走到终点,


s
       

|
       

|
       

|
       

+




e

如图所示(“|”竖走,“—”横走,“+”转弯),易证abs(ex-sx)+abs(ey-sy)为此问题类中任意情况下,起点到终点的最短步数,记做step,此处step1=8;


s



 
 


+
 

|

+
     

|
       

+




e

如图,为一般情况下非最短路径的任意走法举例,step2=14;

step2-step1=6,偏移路径为6,偶数(易证);

结论

编辑

推广之,若 t-[abs(ex-sx)+abs(ey-sy)] 结果为非偶数(奇数),则无法在t步恰好到达;

返回,false;

反之亦反。

原理补充

编辑

鉴于很多同学对奇偶剪枝根本原理的兴趣,所以hj决定再补充一下本词条。

还是以这个为例子吧,现在我把矩阵填满 0 和 1 [1]


0

1

0

1
0
1
0

1

0
1

0

1
0 1 0

1
0 1 0 1

0

1

0

1

0

我们现假设从 0 开始走,则不难证明,

从任意 0 走到任意 1 始终是奇数步;

从任意 0 走到任意 0 始终是偶数步;

引用描述里的“例子”, s 到 e 的最短步数为 t (当然你也可以理解成此时到终点刚好剩余 t 步等等)。

则,我们从 s 到 e 的步数之和(或者说总距离)总可以表示成 sum= t + extra ( extra>=0 ),其中 extra 表示额外的步数。[2]

比如“例子”里面的,做例1吧


s



 
 


+
 

|

+
     

|
       

+




e

此时 t=8,sum=14,所以我们容易得到 extra=6。也就是说按照这个走法,需要在最短的步数上再走额外的 6 步(先不用太在意这些偏移是在什么地方产生的)。

在来一个例2吧,


s



 
 


+
 

|

+
     

|
  + e

+


   

此时,t=7,sum=15,所以我们也容易得到 extra=8。

根据理科生的天性,由这两个一般性的例子,我们很容易嗅察到 extra 都为偶数。先带着疑惑,

再来看我给的 0 、1 矩阵。


0

1

0

1
0
1
0

1

0
1

0

1
0 1 0

1
0 1 0 1

0

1

0

1

0

设左上角坐标为(1,1),右下角坐标为(5,5).

那么我们给的例1,

起点 s 的坐标为(1,1),此点为“0”;

终点 e 为(5,5),此点为“0”。

所以t=8,为偶数。

现在我们再倒过来看,从终点(也就是 e )出发,把最短步数 t=8 耗费掉,不妨这样走,


s
      +
     
+
      |  
    +  
   


e

如图所示从 e (5,5)耗费 8 步走到了(1,5)点。

因为是从 0 走偶数步,所以走到的坐标也一定是 0 ,就像这里的(1,5)点是 0 一样。

这是一个递归的过程,首先如果从0开始,目的地也是0,那末其中的最短距离t必然是个偶数,可其中有可能有障碍物或需要绕弯的情况,那末我们就现将最短距离t用于绕弯,从开始的0,走t步不管怎么走都只能到0,而这个0到终点0的最短路径t也必然是偶数,一直递归下去,直到你绕够了到达终点,这中间你额外的步数都是偶数。

注意到,(1,5)点和起点 s (1,1)都是 0,也就是说,这个 extra 必然是偶数!

再看例2,同样从终点 e 开始耗费 t=7 步,

则所到的点一定是 0 (不管她在哪里),再从这个点回到起点 s ,所用的 extra 也必然是个偶数!

所以无论如何,sum= t + extra ( extra>=0 ) 中的 extra 都是一个偶数

那么我们就可以用公式 t-[abs(ex-sx)+abs(ey-sy)] 计算出extra是否为偶数来判断当前点能否恰好在这么多步到达终点了。

有的同学可能会说以 1 为 起点呢。。其实是一样的啦,自己去捣鼓吧。

核心代码:

ans=t-time-abs(dx-x)-abs(dy-y);
if(ans<0||ans&1) return;

说了这么多,再总结一下吧!

什么是奇偶剪枝?

把矩阵看成如下形式:

0 1 0 1 0 1

1 0 1 0 1 0

0 1 0 1 0 1

1 0 1 0 1 0

0 1 0 1 0 1

从为 0 的格子走一步,必然走向为 1 的格子 。

从为 1 的格子走一步,必然走向为 0 的格子 。

即:

从 0 走向 1 必然是奇数步,从 0 走向 0 必然是偶数步。

所以当遇到从 0 走向 0 但是要求时间是奇数的或者 从 1 走向 0 但是要求时间是偶数的,都可以直接判断不可达!

比如有一地图:

S...
....
....
....
...D

要求从S点到达D点,此时,从S到D的最短距离为s = abs ( dx - sx ) + abs ( dy - sy )。

如果地图中出现了不能经过的障碍物:

S..X
XX.X
...X
.XXX
...D

此时的最短距离s‘ = s + 4,为了绕开障碍,不管偏移几个点,偏移的距离都是最短距离s加上一个偶数距离。

就如同上面说的矩阵,要求你从0走到0,无论你怎么绕,永远都是最短距离(偶数步)加上某个偶数步;要求你从1走到0,永远只能是最短距离(奇数步)加上某个偶数步。

这里我来讲一下搜索中要用到的奇偶剪枝的原理:

看张图,没障碍物#时,S到E的最短路长为6,但是当有障碍物时,就要绕行了

看这张图,黑色为最短路径,当他绕行(红色加蓝色部分)时,其中蓝色部分其实还是最短路径部分平移来的,所以多走的步数也就是红色部分

对于红色部分我们可以分为两部分,一部分是远离最短路径的步数,另一部分是回到最短路径的部分,他们一定是对称的,所以多走的步数一定是偶数!!!

所以要是问走x步能否到达e,就算出最短路径长y,如果x-y是偶数就能到达,否则不能到达!

时间: 2025-01-04 07:01:07

DFS中的奇偶剪枝学习笔记的相关文章

HDU 1010 Tempter of the Bone【DFS经典题+奇偶剪枝详解】

Tempter of the Bone Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 125945    Accepted Submission(s): 33969 Problem Description The doggie found a bone in an ancient maze, which fascinated him a

JavaSE中Collection集合框架学习笔记(2)——拒绝重复内容的Set和支持队列操作的Queue

前言:俗话说“金三银四铜五”,不知道我要在这段时间找工作会不会很艰难.不管了,工作三年之后就当给自己放个暑假. 面试当中Collection(集合)是基础重点.我在网上看了几篇讲Collection的文章,大多都是以罗列记忆点的形式书写的,没有谈论实现细节和逻辑原理.作为个人笔记无可厚非,但是并不利于他人学习.希望能通过这种比较“费劲”的讲解,帮助我自己.也帮助读者们更好地学习Java.掌握Java. 无论你跟我一样需要应聘,还是说在校学生学习Java基础,都对入门和进一步启发学习有所帮助.(关

JavaSE中Collection集合框架学习笔记(3)——遍历对象的Iterator和收集对象后的排序

前言:暑期应该开始了,因为小区对面的小学这两天早上都没有像以往那样一到七八点钟就人声喧闹.车水马龙. 前两篇文章介绍了Collection框架的主要接口和常用类,例如List.Set.Queue,和ArrayList.HashSet.LinkedList等等.根据核心框架图,相信我们都已经对Collection这个JavaSE中最常用API之一有一个较为全面的认识. 这个学习过程,还可以推及到其他常用开源框架和公司项目的学习和熟悉上面.借助开发工具或说明文档,先是对项目整体有一个宏观的认识,再根

CSS中filter滤镜的学习笔记

1.CSS静态滤镜样式 (filter)(只有IE4.0以上支持)  CSS静态滤镜样式的使用方法:{ filter : filtername( parameters1, parameters2, ...) } Filter样式 简要说明 支持参数 alpha 设置图片或文字的不透明度 opacity.finishOpacity.style.startX.startY.finishX.finishY.add.direction.strength blur 在指定的方向和位置上产生动感模糊效果 a

C#中的委托、事件学习笔记

1.委托delegate 委托delegate也是一种类型,在任何可以声明类的地方都可以声明委托,它将方法当做另一个方法的参数进行传递,这样就可以传递不同的方法,完成不同的功能,使程序具有很好的可扩展性. 举例: 假设这里有一台电脑,有人会用它写程序,有人会用它打游戏,有人会用它看电影,有人会用它边听音乐边玩游戏,有人会用它边听音乐边看文档,边上QQ. 这台电脑可以抽象成一个类Computer,里面有个方法DoWork,所有的人都要通过这个方法来做自己的事情. 不用委托的时候我们可以实现一些固定

&lt;&lt;C++标准程序库&gt;&gt;中的STL简单学习笔记

0. 内容为个人学习笔记, 仅供参考, 如有错漏, 欢迎指正! 1. STL中的所有组件都是由模板构成的, 所以其元素可以是任意型别的. 组件有: - 容器: 管理某类对象的集合. 不同的容器有各自的优缺点. - 迭代器: 用来在一个对象集群(Collection of Objects) 的元素上进行遍历. 这个CoB可以是容器/容器的一部分. 每种容器都提供了自己的迭代器. - 算法(Algorithm): 用来处理集群内的元素(比如: 查询,修改,排序等). - 适配器(adapter) -

JavaSE中Collection集合框架学习笔记(1)——具有索引的List

前言:因为最近要重新找工作,Collection(集合)是面试中出现频率非常高的基础考察点,所以好好恶补了一番. 复习过程中深感之前的学习不系统,而且不能再像刚毕业那样死背面试题,例如:String是固定长度的,StringBuffer和StringBuilder的长度是可以变化的.如果一旦问得深入一点,问为什么有这样的区别就傻眼了,只能一脸呆萌地看着面试官. 因此想要通过写文章的形式,系统地总结学习的内容,例如Collection架构是怎样的.有哪些相关的继承和接口实现,这样才能了解什么时候应

JS和JQuery中的事件委托 学习笔记

事件委托其实并不是一个很高级的技巧,比如在一个页面里面,当只存在两个按钮的时候,可能你给按钮添加监听是这样的:(本文不考虑浏览器兼容性,关于事件的兼容性可参考前面的学习笔记) <div id="container"> <button id="btn1">按钮1</button> <button id="btn2">按钮2</button> </div> var btn1 =

HDU - 1010 (DFS回溯法 + 奇偶剪枝)

题目大意:给出一个N*M的迷宫,迷宫中有一扇门D,只有在T时刻会打开,现在你0时刻位于S,你需要在正好在T时刻到达D,你只能上下左右移动,每次移动耗费1时刻,且同一个位置不能进入两次,问是否能在T时刻刚好到达D处. 范围 1 < N,M < 7, 1 < T < 50,这个范围有点大,直接DFS回溯搜会TLE,我们要加上一个剪枝,这个剪枝十分重要,我们求出起点到终点的距离(横向距离 + 纵向距离),若这个距离为奇数,则时间T必须也要为奇数,否则时间T必须为偶数(其中的道理显而易见)