搜索剪枝(魔方为例)
剪枝技术的技巧
剪枝技术的技巧
剪枝技术是在搜索算法中用来减少搜索空间以提高效率的一种技术。
以下是一些常见的剪枝技巧:
1. 回溯剪枝:当进行回溯搜索时,可以通过判断当前搜索路径是否符合要求,如果不符合则可以提前终止当前路径的搜索,从而减少不必要的搜索。
2. 前向剪枝:在搜索过程中,可以通过一些策略来判断一些分支是否有必要继续搜索下去。
比如,通过估计某个分支的上下界来判断该分支是否可能包含最优解,如果不包含则可以直接剪掉该分支,从而减少搜索空间。
3. 对称剪枝:当问题存在对称性质时,可以利用对称性质来减少搜索空间。
比如,棋盘游戏中,如果对称的局面是等价的,则可以只搜索其中一部分的局面,然后利用对称性质进行复制和旋转,得到其他等价的局面。
4. 剪枝函数的设计:在问题中,可以通过设计剪枝函数来减少搜索空间。
剪枝函数可以根据问题的特性和要求来判断某个搜索节点下的子节点是否需要继续搜索。
比如,在搜索字典树的时候,可以使用剪枝函数判断某个前缀是否是合法的单词,如果不是则可以剪掉该分支。
5. 启发式搜索:启发式搜索是一种基于问题特性和经验的搜索技术,可以通过估计搜索节点的优劣程度来决定搜索优先级。
在搜索过程中,可以通过选择优先
级高的节点来先进行搜索,从而提高效率。
比如,在迷宫问题中,可以通过估计每个节点到目标点的距离来进行搜索,选择距离最短的节点先进行搜索。
这些技巧可以根据具体的问题和算法进行灵活运用,以提高搜索效率。
参数空间 剪枝
参数空间剪枝
剪枝是一种常见的技术手段,用于减少参数空间的大小,从而提高算法的效率和性能。
参数空间剪枝可以应用于各种领域,包括机器学习、优化算法等。
在机器学习中,参数空间剪枝可以用于减少模型的复杂度,提高训练速度和泛化能力。
在训练模型时,通常需要搜索一定的参数空间,以找到最优的参数组合。
然而,参数空间往往非常庞大,搜索起来非常耗时。
因此,剪枝技术可以用来缩小参数空间,减少搜索的时间和计算量。
在优化算法中,参数空间剪枝可以用于减少搜索空间,加速求解过程。
优化问题通常可以转化为在参数空间中搜索最优解的问题。
然而,参数空间往往非常庞大,搜索起来非常困难。
因此,剪枝技术可以用来减少搜索空间,提高求解效率。
剪枝技术有很多种方法,包括基于规则的剪枝、基于启发式的剪枝、基于模型的剪枝等。
基于规则的剪枝方法通常通过定义一些规则,来剪除一些不符合规则的参数组合。
基于启发式的剪枝方法通常通过一些启发式的方法,来剪除一些不可能是最优解的参数组合。
基于模型的剪枝方法通常通过训练一个模型,来预测哪些参数组合是不可能是最优解的。
在实际应用中,剪枝技术能够显著提高算法的效率和性能。
通过剪
枝,可以减少搜索的时间和计算量,从而加快求解过程。
同时,剪枝还可以减少模型的复杂度,提高模型的泛化能力。
因此,参数空间剪枝是一种非常有用的技术手段,值得在各种应用中广泛使用。
魔方解法大全(超简单超全带图片)
12图1 魔方底层架十字可以无师自通,只是我们这一步要复原的四个棱块的相对位置顺序要注意,由于我们以白色中心块做底层,按照我们现在的主流魔方的贴纸的帖法(上黄下白,前蓝后緑,左橙右红),如果我们先复原了白蓝这个棱块,那我们在保持白色中心块在底部的情况下,白红的棱块就一点要放在白蓝棱块的右边,白橙棱块放在白蓝棱块的左边,白緑棱块放在白蓝棱块的对面,由于魔方的中心块不会发生变化,所以在复原的过程中,我们是以中心块为参照物的,第一步我们在复原白蓝、白红、白绿、白橙这四个棱块的时候,我们可以先把白色面旋转到顶层,和黄色中心块同一个平面,然后再把他对应的另一个颜色(蓝或红或緑或橙)经过旋转最上层,使之和对应的中心块的颜色同色,这样我们再旋转180度,对应的棱块就正确复原到底部了。
注意:图101的情况是没有正确归位的情况,需要调整白蓝和白红两个棱块的位置,才是正确的完成了底棱归位图101第二步:底角归位(复原魔方第一层四个角块)图2 魔方的四个底角正确归位以后一定会出现倒T字型,如图2所示,如果不是这样肯定是底面角块没有正确归位(位置错了,重新来过)。
底角归位也可无师自通,有兴致的朋友可以自己琢磨一些技巧和完成这一步。
有难度的朋友可参考我下面介绍的一种技巧来完成,我们先看图2-1和图2-2,首先我们先确定目标块的位置是在他要正确归位的正上面的位置,然后我们再看白色的面朝向何方,就很快的能快速判断出来是下图几种情况中的哪一种了。
复原基本思想:先将目标角块调至顶层侧面,再转动能与之相连形成顺色整体的面,使目标角与底棱连成一个(1×1×2)的归位整体,再转至正确的位置。
因此,下列的五个实例并没有必要当成公式来死记。
3图2-1 图2-2 公式2-1:(R U R')公式2-2:(F'U'F)记忆技巧:白色朝右,第一步就旋转右层记忆技巧:白色朝前,第一步就旋转前层图201 图202 图203 用两次公式2-1 用两次公式2-2 用三次公式2-1(R U R') U' (R U R')(F'U'F)U (F'U'F)(R U R')(R U R') U' (R U R')第三步:中棱归位(复原魔方中层四个棱块的步骤)4图3 魔方中间层共有四个棱块,也只是四个棱块需要复原(注意中间层没有角块哟),图3-1和图3-2是两个比较常见的情形,我们主要介绍的就是这两种情况的复原方法,仔细分析比较这两个公式,步骤虽然有点多,可是很好记忆哟。
魔方速解法-桥式
魔方速解法-桥式桥式魔方,又称北桥魔方,源自于美国小伍德斯托克特 (Woodstock) 县一位古典魔方高手 Peter Comier 所发明,它以其独特又神秘的外形,迅速赢得了魔友们的喜爱,在很短的时间里即成为独特的收藏品及拼图玩具。
桥式魔方的样式特点主要为特殊的立体桥形状,组合出六面立体的三维魔方,且不仅具有旋转的空间维度,橫向亦有移动的特色,它所具有的特殊复杂的几何设计,更加将魔方推向极致,是玩家们需要重新梳理六面立体桥魔方进行速解的不二之选,其所承载的独特文化更是吸引众多爱好玩家的喜爱,成为当下数字魔方领域迷人的存在。
桥式魔方的解法和其它魔方的解法一样,也可以采用通用的式法来完成。
第一步,把桥式魔方展开,方便熟悉桥体的形状,包括桥头(mouth)、桥面(face)以及桥的两侧(right side and left side),亦可熟悉魔方解法的基本概念(cross、f2l、oll、pll);第二步,整体不动的情况下,根据特定的步骤方法摆放每个角块(corner cube)以及正中心块(edge cube),只能够旋转每一层所对应的魔方,而不能够勾动任何隔离的块,完成角块和正中央块的装订;第三步,在每一层魔方大致形成正确形状以后,便可将其与中心块(center cube)旋转搭配在正确摆立;最后一步,在保持每一层魔方不动的基础下,使用一系列的套路连结六面的魔方,完成六面立体桥魔方的速解,完成难度较高,但也在可接受范围内的解题流程。
通过上述步骤,理解桥式魔方六面立体解法,桥式魔方可以在不分层次提取每个旋转块具体位置的前提下,完成六面立体整合,而解法上非常类似普通的三维立体魔方,只需要简单熟悉特殊部件的空间结构,即可完成桥式魔方的立体速解。
桥式魔方在速解上较普通的魔方突显出自己的独特性,这正因为桥的整体结构,使其表现出一种让用户更容易完成速解的多面模型,而解法上也需要一定的反复观察,才能完成一个完美的立体桥结构,追求完美解题是玩家们需要努力探寻的答案,并在更多时间内完成魔方的速解,通过这样的精细解题,可以最大程度的强化习得熟练的解题技能,在有趣的魔方游戏中,赢之未敢忘。
α-β剪枝技术解题过程
4.15
• 设有如图4.35所示的博弈树,其中最下面的 数字是假设的估值,请对该博弈树做如下 工作:
– 计算各节点的倒退值; – 利用α-β剪枝技术剪去不必要的分支。
4.15
S0 A C D E B F
G
H
I
J
K
L
M
N
0
5
-3
3
3
6
-2
3
5
4
-3
0
6
8
9
-3
4.15 解答
S0 A C ≥0 D E B F
G
0
H
≤-3
I
J
K
L
M
N
0
5
-3
3
3
6
-2
3
5
4
-3
0
6
8
9
-3
4.15 解答
S0 A C ≥0 0 ≤0 D ≥3 E B F
G
0
H
≤-3
I
3
J
K
L
M
N
0
5
-3
*
3
6
-2
3
5
4
-3
0
6
8
9
-3
4.15 解答
≥0 S0 A C 0 ≤0 D ≥3 E ≥4 B F
G
0
H
≤-3
I
3
*
K
4
L
-3
M
N
α-β剪枝技术 知识点 剪枝技术-剪枝技术
• α-β剪枝技术 剪枝技术 首先分析极小极大分析法效率,上述的极小极大分析法,实际是先生成一棵博弈树,然后再计 算其倒推值,至使极小极大分析法效率较低。于是在极小极大分析法的基础上提出了α-β剪枝技术 。 α-β剪枝技术的基本思想或算法是,边生成博弈树边计算评估各节点的倒推值,并且根据评估 出的倒推值范围,及时停止扩展那些已无必要再扩展的子节点,即相当于剪去了博弈树上的一些分 枝,从而节约了机器开销,提高了搜索效率。具体的剪枝方法如下: (1) 对于一个与节点MIN,若能估计出其倒推值的上确界β,并且这个β值不大于 MIN的父节点( 一定是或节点)的估计倒推值的下确界α,即α≥β,则就不必再扩展该 MIN节点的其余子节点了(因为 这些节点的估值对MIN父节点的倒推值已无任何影响 了)。这一过程称为α剪枝。 (2) 对于一个或节点MAX,若能估计出其倒推值的下确界α,并且这个α值不小于 MAX的父节点( 一定是与节点)的估计倒推值的上确界β,即α≥β,则就不必再扩展该MAX节点的其余子节点了(因为 这些节点的估值对MAX父节点的倒推值已无任何影响 了)。这一过程称为β剪枝。 从算法中看到: (1) MAX节点(包括起始节点)的α值永不减少; (2) MIN节点(包括起始节点)的β值永不增加。 在搜索期间,α和β值的计算如下: (1) 一个MAX节点的α值等于其后继节点当前最大的最终倒推值。 (2) 一个MIN节点的β值等于其后继节点当前最小的最终倒推值。
魔方的解法(初级)
魔方的解法(初學者)魔方的解法很多,主要分為2個類別:層先歸位(逐層完成)及角塊先歸位(先完成角位);以這2個方法為基礎,發展出很多不同的解法。
而現在所用的快速解法是以層先歸位的方法。
這個方法:● 先在其中一面做1個“十”字,完成第1層 ● 然後再做第2層 ● 最後做第3層這是個初階的方法,要記熟幾個步驟。
若能熟練的話,可以在60秒以內完成。
有些人甚至可以在20-30秒內完成。
但初學者不用太介懷時間,只要掌握步驟就可以,並加以練習,就可以熟練,然後再學其他高級的方法。
這個方法除了不用記太多步驟外,還有其他好處,是容易知道自己在哪兒出錯。
若你想學習更多高級的解法的話,就可以再多記其他步驟,成為魔方的高級專家。
魔方的經構三階魔方共有27棱塊(3 x 3 x 3);有6個中心點、8個角塊、12條棱邊。
中心點可以在自己的軸上自由轉動,而角和棱邊可以繞著中心點轉動。
術語要了解以後所述的魔方解法,先行了解簡單的術語。
魔方有6面:前(F )、後(B )、上(U )、下(D )、左(L )、右(R )。
魔方還有2個主要術語:棱塊、角塊。
注意下列要點:● 1個英文字母代表要把該面順時針方向轉動 ● 1個英文字母上加上小撇(’),代表要逆時針方向轉動 ● 若在英文字母後加上2,代表要轉180°● 括號代表要把有關步驟組合成一組,方便學習較長的步驟例如:RU ’L2這個步驟代表要把右面往順時針方向轉90°,然後上層往逆時針方向轉90°,最後左面順時針方向轉180°。
下後上 右上 左 棱塊 角塊解法第1層要使第1層歸位,有2個階段: ● 先做出“十”字(解決棱塊) ● 使角塊歸位緊記:每塊棱塊和角塊在不同面上的顏色都不同,這個就是代表不同的棱塊和角塊其實是有特定位置。
首先做“十”字解法的第1步是先要使上層轉出1個白色“十”字,使棱塊都是白色向上。
第1步要做出“十”字,要因應不同情況而轉動魔方,使棱塊轉到X 的位置。
剪枝搜索法求解选择问题
剪枝搜索法求解选择问题1.问题的描述选择问题:给定n个元素,要求确定其中的第k小元素。
解决该问题的一种方法是先将n 个元素排序,然后从有序序列中确定第k小元素。
因为排序算法的时间复杂度是O(nlogn),所以这也决定了该方法在最坏情况下的时间复杂度是O(nlogn)。
应用剪枝搜索策略可以在线性时间内解决选择问题(select problem)。
2.通过剪枝搜索法求解选择问题的算法思想确定不包含第k小元素的那部分元素,在每次迭代时将该部分剪除。
要得到O(n)时间的算法,必须在每次迭代时用O(n)时间剪去部分元素。
令S表示输入数据集合,p为S中某元素。
可以把S分成S1、S2和S3三个子集,其中S1中包含所有小于p的元素,S2中包含所有等于p的元素,S3中包含所有大于p的元素。
如果S1集合中的元素个数大于k,那么可以确定S的第k小元素就在S1中,并且在接下来的迭代中可以剪去S2和S3; 否则,如果S1和S2元素个数之和大于k,那么p就是S的第k小元素;如果上面情况均不满足,那么S的第k小元素必大于p。
这样,可以丢弃S1和S2,在下次迭代时,重新开始从S3中找出第(k−|S1|−|S2|)小元素。
关键点是如何选择p,使在每--次迭代时都能丢弃S的一部分,不管该部分是S1、S2还是S3。
可以按如下方法选择p:首先,将n个元素分成每5个元素形成一个集合的[n/5]个子集。
如果需要,可以在最后的子集中加入虚拟元素∞。
然后,对每个5元素子集排序,从每个子集中选出中位数形成新序列M={m1,m2,…,muisp},并令p为M中位数。
如图1所示,S中至少有1/4元素小于或等于p,至少1/4的元素大于或等于p。
这样,如果按照这种方法选择p,那么在每次迭代时总能剪去S中至少n/4的元素。
图 13.算法描述输入元素个数后,使其索引从0开始,那么第k小的元素就是把所有数组元素从小到大排序后索引在k−1位置上的元素。
Partition函数:将给定的数组元素根据第一个元素进行划分。
应用Freemat软件---结合剪枝法解出六角幻方的答案
應用Freemat軟件---結合剪枝法解出六角幻方的答案何耀堂劉冠靈一、前言由1910年至1962,共花了52年時間,通過不斷嘗試,終於找出二階六角幻方(圖3)的答案;在1969年滑鐵盧大學二年級學生阿萊爾對特裡格的結論作了簡單而又巧妙的證明[2],他又把六角幻方的可能選擇輸入電子計算機測試,結果用了17秒時間,得出了與阿當斯完全相同的結果。
由此可見利用適當的條件,結合計算機的力量,節省不少時間,因此本文嘗試用這個角度來進行,本文主要介紹六角幻方怎樣用窮舉法,結合適當的數學條件(剪枝法),通過FreeMath計算出它的唯一解。
二、六角幻方------建模過程每條直線上的數字之和相等。
如圖,橫行有5行,故每一直線的數字之和是190538÷=。
因每一直線的數字之和是38,結合圖(1a),則滿足以下十五條條件為﹕38A B C ++= …………(1) 38C G L ++= …………(2) 38L P S ++= …………(3) 38S R Q ++= …………(4) 38Q M H ++= (5)38H D A ++=…………(6) 38D E F G +++=…………(7) 38D I N R +++=…………(8) 38G K O R +++= …………(9) 38B E I M +++= …………(10) 38B F K P +++=…………(11) 38M N O P +++= (12)38A E J O S ++++= …………(13) 38C F J N Q ++++=…………(14) 38H I J K L ++++= (15)如右圖,如果得知E 、F 、K 、O 、N 、I 的數值,便能計算出B 、G 、P 、R 、M 、D 和J 的數值。
由(7)(8)(9)+-得238D E F I N K O ++++--=整理得[]138()()()2D E F I N K O =-+-+++ (16)同理可得[]138()()()2G E F K O I N =-+-+++ …………(17) []138()()()2R IN K O E F =-+-+++ (18)[]138()()()2B E I F K N O =-+-+++ …………(19) []138()()()2M EI N O F K =-+-+++ …………(20) []138()()()2P FK N O E I =-+-+++ (21)已知E 、F 、K 、O 、N 、I ,計算J 的步驟比較複雜,如下﹕ 由(13)得 38()()J E O A S =-+-+ …………(*)由(1)(3)(2)+-得 38()A S B P G +=-++ …………(**) 由(11)得 38()B P F K +=-+ 代入(**)得 ()A S F K G +=++ 代入(*)得38()()J E O F K G=-+-++ 以(17)的G 值代入上式得 []138()()38()()()2J E O F K E FK OI N =-+-+--+-+++整理得119()2J E F K O N I =-+++++ (22)因為在J 的圓圈中只能填入1-19,所以119J ≤≤,故由(22)得0()36E F K O N I ≤+++++≤ (23)三、六角幻方------利用計算機過程我們會用開源軟件freemat 幫助篩選出合適的答案,首先找出要符合條件的E 、F 、K 、O 、N 、I 的所有組合,從19個取6個數的組合數為61927132C =(種)利用條件(23)和根據(22)計算出J 的值,因J 必須為整數的條件篩選後,剩下78種組合(經過運行test_step1.m 代碼運算所得,需時約39秒)。
搜索方法中的剪枝优化
下面我们举一个例子——Betsy 的旅行(USACO)。
题目简述:一个正方形的小镇被分成N 2个小方格,Betsy 要从左上角的方格到达左下角的方格,并且经过每个方格恰好一次。
编程对于给定的N ,计算出Betsy 能采用的所有的旅行路线的数目。
实际上,由于Betsy 的每一次移动,只会影响到附近的格子,所以每次执行剪枝判断时,应当只对她附近的格子进行检查:对于第一个剪枝条件,我们可以设一个整型标志数组,分别保存与每个格子相邻的没被经过的格子的数目,Betsy 每次移动到一个新位置,都只会使与之相邻的至多4个格子的标志值发生变化,只要检查它们的标志值即可。
而对于第二个剪枝条件,处理就稍稍麻烦一些。
但我们仍然可以使用局部分析的方法,即只通过对Betsy 附近的格子进行判断,就确定是否应当剪枝,下图简要说明了剪枝的原理:上图给出了可以剪枝的三种情况。
由于Betsy 到过的所有格子都一定是四连通的,所以每种情况下的两个白色的格子之间必定是不连通的,它们当中必然至少有一个是属于某个孤立区域的,都一定可以剪枝。
一、 优性剪枝下面举一个应用最优性剪枝的典型例题——最少乘法次数。
题目简述:由x 开始,通过最少的乘法次数得出n x ,其中n 为输入数据。
(参见参考书目1)因为两式相乘等于方幂相加,所以本题可以等效的表示为:构造一个数列{}i a ,满足⎩⎨⎧><<=+==)1(),1()1(1i i k j a a i a k ji 要求n a t =,并且使t 最小。
我们选择回溯法作为本程序的主体结构:当搜索到第i 层时,i a 的取值范围搜索中的剪枝优化在11+-i a 到2*1-i a 之间,为了尽快接近目标n ,应当从2*1-i a 开始从大到小为i a 取值,当然,选取的数都不能大于n 。
当搜索到n 出现时,就得到了一个解,与当前保存的解比较取优。
最终搜索结束之后,即得到最终的最优解。
DFS(四):剪枝策略
DFS(四):剪枝策略顾名思义,剪枝就是通过⼀些判断,剪掉搜索树上不必要的⼦树。
在采⽤DFS算法搜索时,有时候我们会发现某个结点对应的⼦树的状态都不是我们要的结果,这时候我们没必要对这个分⽀进⾏搜索,砍掉这个⼦树,就是剪枝。
在DFS搜索算法中,剪枝策略就是寻找过滤条件,提前减少不必要的搜索路径。
应⽤剪枝策略的核⼼问题是设计剪枝判断⽅法,即确定哪些枝条应当舍弃,哪些枝条应当保留的⽅法。
剪枝策略按照其判断思路可⼤致分成两类:可⾏性剪枝及最优性剪枝。
1.可⾏性剪枝可⾏性剪枝就是把能够想到的不可能出现的情况给它剪掉。
该⽅法判断继续搜索能否得出答案,如果不能直接回溯。
【例1】Sum It Up (POJ 1564)DescriptionGiven a specified total t and a list of n integers, find all distinct sums using numbers from the list that add up to t. For example, if t = 4, n = 6, and the list is [4, 3, 2, 2, 1, 1], then there are four different sums that equal 4: 4, 3+1, 2+2, and 2+1+1. (A number can be used within a sum as many times as it appears in the list, and a single number counts as a sum.) Your job is to solve this problem in general.InputThe input will contain one or more test cases, one per line. Each test case contains t, the total, followed by n, the number of integers in the list, followed by n integers x 1 , . . . , x n . If n = 0 it signals the end of the input; otherwise, t will be a positive integer less than 1000, n will be an integer between 1 and 12 (inclusive), and x 1 , . . . , x n will be positive integers less than 100. All numbers will be separated by exactly one space. The numbers in each list appear in nonincreasing order, and there may be repetitions.OutputFor each test case, first output a line containing `Sums of', the total, and a colon. Then output each sum, one per line; if there are no sums, output the line `NONE'. The numbers within each sum must appear in nonincreasing order. A number may be repeated in the sum as many times as it was repeated in the original list. The sums themselves must be sorted in decreasing order based on the numbers appearing in the sum. In other words, the sums must be sorted by their first number; sums with the same first number must be sorted by their second number; sums with the same first two numbers must be sorted by their third number; and so on. Within each test case, all sums must be distinct; the same sum cannot appear twice.Sample Input4 6 4 3 2 2 1 15 3 2 1 1400 12 50 50 50 50 50 50 25 25 25 25 25 250 0Sample OutputSums of 4:43+12+22+1+1Sums of 5:NONESums of 400:50+50+50+50+50+50+25+25+25+2550+50+50+50+50+25+25+25+25+25+25(1)编程思路。
算法笔记--极大极小搜索及alpha-beta剪枝
算法笔记--极⼤极⼩搜索及alpha-beta剪枝极⼩极⼤搜索算法即minimax搜索算法主要应⽤于零和博弈(⾮胜即负,如围棋,象棋,井⼦棋等),完全信息(玩家知道之前所有的步骤。
象棋就是完全信息,因为玩家是交替着落⼦,且之前的步骤都能在棋盘上体现)这个算法采⽤搜索算法递归实现,⼀层为先⼿,记为a, ⼀层为后⼿,记为b, 交替出现对于最终局⾯,有⼀个分数(⽐如:先⼿胜分数为1,平局分数为0,先⼿输分数为-1)先⼿a想要让这个分数越⼤越好,后⼿b想要让这个分数越⼩越好,于是搜索到先⼿这⼀层,取最⼤返回,搜索到后⼿这⼀层,取最⼩返回如下图:于是伪代码为:int MaxMin(position,int d){int bestvalue,value;if(game over) //检查游戏是否结束return evaluation(p);// 游戏结束,返回估值if(depth<=0) //检查是否是叶⼦节点return evaluation(p);//叶⼦节点,返回估值if(max) //极⼤值点bestvalue=-INFINTY;else//极⼩值点bestvalue=INFINTY;for(each possibly move m){MakeMove(m); //⾛棋value=MaxMin(p,d-1);UnMakeMove(m); //恢复当前局⾯if(max)bestvalue=max(value,bestvalue);//取最⼤值elsebestvalue=min(value,bestvalue);//取最⼩值}return bestvalue;}关于alpha-beta剪枝:如果当前层为取最⼩,如果取最⼩后⽐上⼀层当前最⼤值还⼩,则不需要往下搜索,因为上⼀层根本不会选择当前节点往下搜,还有更好的选择同理,如果当前层为取最⼤,如果取最⼤后⽐上⼀层当前最⼩值还⼤,则不需要往下搜索,因为上⼀层根本不会选择当前节点往下搜具体推荐看最上⾯的知乎链接点赞最多的回答。
第4讲 搜索剪枝
教研研究院
C++
NOIP
NOI
IOI
题目描述在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。多多决定把所有的果子合成一堆。每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。可以看出,所有的果子经过 n−1 次合并之后, 就只剩下一堆了。多多在合并果子时总共消耗的体力等于每次合并所耗体力之和。因为还要花大力气把这些果子搬回家,所以多多在合并果子时要尽可能地节省体力。假定每个果子重量都为 1,并且已知果子的种类 数和每种果子的数目,你的任务是设计出合并的次序方案,使多多耗费的体力最少,并输出这个最小的体力耗费值。例如有 3 种果子,数目依次为 1 , 2 , 9 。可以先将 1 、 2 堆合并,新堆数目为 3 ,耗费体力为 3 。接着,将新堆与原先的第三堆合并,又得到新的堆,数目为 12 ,耗费体力为 12 。所以多多总共耗费体力=3+12=15 。可以证明 15 为最小的体力耗费值。正整数N(N≤26)。后面的三行,每行有一个由大写字母组成的字符串,分别代表两个加数以及和。这3个字符串左右两端都没有空格,从高位到低位,并且恰好有N位。输出格式:一行,即唯一的那组解。解是这样表示的:输出N个数字,分别表示A,B,C,…所代表的数字,相邻的两个数字用一个空格隔开,不能有多余的空格。
合并果子
输入输出格式
输入输出样例
1
PART ONE
题目描述所谓虫食算,就是原先的算式中有一部分被虫子啃掉了,需要我们根据剩下的数字来判定被啃掉的字母。来看一个简单的例子: 43#9865#045+ 8468#6633 44445509678其中$#$号代表被虫子啃掉的数字。根据算式,我们很容易判断:第一行的两个数字分别是5和3,第二行的数字是5。现在,我们对问题做两个限制:首先,我们只考虑加法的虫食算。这里的加法是N进制加法,算式中三个数都有N位,允许有前导的0。其次,虫子把所有的数都啃光了,我们只知道哪些数字是相同的,我们将相同的数字用相同的字母表示,不同的数字用不同的字母表示。如果这个算式是N进制的,我们就取英文字母表午的前N个大写字母来表示这个算式中的0到N−1这N个不同的数字:但是这N个字母并不一定顺序地代表0到N−1。输入数据保证N个字母分别至少出现一次。 BADC+CBDA DCCC上面的算式是一个4进制的算式。很显然,我们只要让ABCD分别代表0123,便可以让这个式子成立了。你的任务是,对于给定的N进制加法算式,求出N个不同的字母分别代表的数字,使得该加法算式成立。输入数据保证有且仅有一组解。
魔方全解(比较简单的几种解法)
魔方全解(比较简单的几种解法)LT三阶魔方一、魔方构造1.魔方共六个面,每个面有一种颜色,若以红面为正面,绿面为底面,则橙面为背面,蓝面为顶面,白面为左面,黄面为右面。
2.三阶魔方由3×3×3=27块小正方体构成,其中一块在内部,没有颜色;6块只有一种颜色,叫做中心块;12块有两种颜色,叫做边块;8块有三种颜色,叫做角块。
3.只要魔方任意三块小正方体连成一线,就能旋转。
4.三阶魔方中心块的位置不会改变。
5.魔方还原的前提是有一个被转乱的魔方。
二、转向表示为了方便表示魔方的转向,使用以下字母。
(箭头所指为前面)1.一层旋转F (Front ) 中心块边块F 将魔方前面一层顺时针旋转90度。
Fi 将魔方前面一层逆时针旋转90度。
B (Back )B 将魔方后面一层顺时针旋转90度。
Bi 将魔方后面一层逆时针旋转90度。
L (Left )L 将魔方左面一层顺时针旋转90度。
Li 将魔方左面一层逆时针旋转90度。
R (Right )R 将魔方右面一层顺时针旋转90度。
Ri 将魔方右面一层逆时针旋转90度。
U (Up )U 将魔方上面一层顺时针旋转90度。
Ui 将魔方上面一层逆时针旋转90度。
D (Down )D 将魔方下面一层顺时针旋转90度。
Di 将魔方下面一层逆时针旋转90度。
2.中间层旋转F Fi B BiL Li R Ri U Ui D Di·通常,单个字母表示顺时针旋转,加i或ˊ表示逆时针旋转。
·双写转向或在转向后加2表示在这个方向上旋转180度。
·()×n表示重复括号内的步骤n次。
三、魔方还原1.一面(一层)还原1)还原一面边块①选择好一种颜色的中间块作为要还原的一面,将其作为前面,记住它的背面中间块颜色。
②先恢复一个色块,以这个色块为准,旋转前面使上、下、左、右四面中心块正位。
③旋转后面一层或第二层使其出现下面情况,逐个恢复色块,直到前面形成十字。
魔方指法练习FSC
魔方指法练习FSC关于魔方指法练习(FSC)FSC:finger shortcut“手指捷径”,指魔方速度还原中的基本手法。
就是利用手指头来转动方块,减少换手所产生的时间,以往我们都是用手腕来转动方块,在换方向时,我们习惯把手拿起来换位置,这时已经造成时间的浪费了,玩方块若以「速度」为目标的话,那么FSC就为必要的一项技能。
基本用法然后我们作「U'」,这时就是用左手的食指来推方块。
当我们作「U」时,则是用右手食指来推方块。
以上为最基本的用法,其实FSC的变化非常的多,需要靠每个人自己去探索,找出自己顺的手法,更进阶的还会有「大拇指的FSC」,或是变换角度然后左右手同时用...等等。
(R U R') U用右手食指推(R' U' R) U'用左食指推(R' U R') 三步全用右食指一气呵成(R U' R') U'用左食指推(R U' R) 三步全用右大拇指一气呵成(R' U2) 第一手R'和第二手U2中的一半用右食指。
第二手剩下来的用右中指。
(R U2') 第一手R'和第二手U2'中的一半U'用右大拇指。
第二手剩下来的U'用左食指。
(R2 U') 全用右大拇指一气呵成。
(R' F' R) (F' R)用右大拇指一气呵成。
(R' F R F') (R F' )用右大拇指一气呵成。
(U U' u u' U2 U2' u2 u2') U、U'等系列是魔术方块极为重要的手法。
平常多转U、U'等系列来练习吧。
(R U R' U')*6(R U' R' U )*6(R' F R F')*6下面是详解3阶魔方手法要点如果你有一个国甲之类的专业型魔方,你就可以做到高手录像中用手指拨动魔方的动作,以下为3阶魔方手法中的要点。
NOI导刊 搜索顺序的选取与剪枝策略
生日蛋糕(NOI99)
条件1:V = nπ
H=m层
形状:每层都是一个圆柱体。
条件2:
设从下往上数第i(1<=i<=m)层蛋糕是半径为Ri, 高度为Hi的圆柱。 当i<m时,要求Ri>Ri+1且Hi>Hi+1。 条件3:
表面积Q最小,令Q= Sπ
问题:
给出的n和m,
]
Else if Vi =0 then 更新最优值
• Problem-Cake
1. 计算MINi和MAXi R,H ; 2. for R1m to sqrt ( n ) do
/*假设 H1=1,只做一层蛋糕 */
3. for H1n div (R1*R1) downto m do [
4.
S1=2 * R1* H1+ R1* R1
mi
MINi k3 k1
因此,剪枝条件为, if Vi< MINi then exit
优化??
(3)如果剩下的蛋糕材料太多,以最大的方式做完m层, 仍有材 料剩余,那么没有必要继续往下做了,设, 第i+1层半径和高分别为,Ri+1 = Ri – 1 , Hi+1 = Hi –1 第i+2层半径和高分别为,Ri+2 = Ri – 2 , Hi+2 = Hi –2 ………… 第 m层半径和高分别为,Ri+m = Ri –m ,Hi+m= Hi –m 这样, 余下的m-i层的最大体积为
then exit; {剪枝1} {剪枝2} {剪枝3}
if i<m then
for Ri + 1 Ri downto i for Hi + 1min(Vi div (Ri + 1*Ri + 1), Hi) downto i [ Si + 1Si + 2 * Ri + 1* Hi + 1 Vi + 1Vi - Ri + 1* Ri + 1* Hi + 1 Search ( i+1, Ri + 1, Hi + 1, Si + 1,Vi + 1)
搜索剪枝常见方法与技巧
这道题,因为很难找到数学规律,便只有采用搜索的方法。 首先,第一感觉便是:从城市 i 出发,便搜索所有相邻的城市,再根据当前所处的 城市,确定任务的完成情况,从中找到最优解。这种搜索的效率是极低的,其最大 原因就在于:目标不明确。 根据题意,我们只需到达需上货和下货的城市,其它的城市仅作为中间过程, 而不应作为目标。因此,首先必须确定可能和不可能完成的任务,然后求出任意两 城市间的最短路径。在搜索时,就只需考虑有货要上的城市,或者是要运到该城市 的货全在车上,其它不须考虑。同时,还可以设定两个简单的槛值。如果当前费用 +还需达的城市>=当前最优解,或当前费用+返回城市 1 的费用>=当前最优解,则 不需继续往下搜索。 这种方法与第一感的方法有天壤之别。(附程序 travell.pas) 问题三:(多处理机调度问题) 设定有若干台相同的处理机 P1,P2Pn,和 m 个独立的作业 J1,J2jm,处理机以 互不相关的方式处理作业,现约定任何作业可以在任何一台处理机上运行,但未完 工之前不允许中断作业,作业也不能拆分成更小的作业,已知作业 Ji 需要处理机 处理的时间为 Ti(i=1,2m)。编程完成以下两个任务: 任务一:假设有 n 台处理机和 m 个作业及其每一个作业所需处理的时间 Ti 存放在 文件中,求解一个最佳调度方案,使得完成这 m 个作业的总工时最少并输出最少工 时。 任务二:假设给定作业时间表和限定完工时间T于文件中,求解在限定时间T内完 成这批作业所需要最少处理机台数和调度方案。 此题有两种搜索方法: 方法一:按顺序搜索每个作业。当搜索一个作业时,将其放在每台处理机搜索 一次。 方法二:按顺序搜索每台处理机。当搜索一台处理机时,将每个作业放在上面 搜索一次。
3
对比上述两种方法,可以发现:方法二较方法一更容易剪枝。 下面是两中方法剪枝的对照: 对于方法一:只能根据目前已确定的需时最长的处理机的耗时与目前最佳 解比较。 对于方法二:可约定 Time[1]>Time[2]>Time[3]> >Time[n](Time[i]表 示第 i 台处理机的处理时间),从而可以设定槛值:如当前处理机的处理时间>= 目前最佳解,或剩下的处理机台数×上一台处理机的处理时间<剩余的作业需 要的处理时间,则回溯。因为在前面的约束条件下,已经不可能有解。 因此,从上面的比较来看,第二种方法显然是比第一种要好的。下面就针 对第二种方法更深一层的进行探讨。 对于任务一,首先可以用贪心求出 Time[1]的上界。然后,还可以 Time[1] 的下界,UP(作业总时间/处理机台数)。(UP 表示大于等于该小数的最小整 数)。搜索便从上界开始,找到一个解后,若等于下界即可停止搜索。 (附程序 jobs_1.pas) 对于任务二, 可采用深度+可变下界。 下界为: UP (作业总时间/限定时间) , 即至少需要的处理机台数。并设定 Time[1]的上界为 T。 (附程序 jobs_2.pas)
dfs剪枝经典例题
DFS剪枝经典例题包括「木棍加工」和「最小矩形覆盖」等。
「木棍加工」问题描述:给定一个长度为n的数组,表示n根木棍的长度。
现在需要将这些木棍加工成一些小段,要求每个小段的长度都相同,并且这些小段的数量要尽可能多。
求这些小段的最大可能长度。
这个问题可以使用DFS搜索+剪枝来解决。
具体做法是先对木棍长度进行排序,然后从大到小枚举每个长度作为小段的可能长度,使用DFS搜索来检查是否能够将所有木棍切割成这个长度的小段。
在DFS搜索的过程中,可以使用一些剪枝技巧来提前结束搜索,例如:如果当前搜索到的木棍长度已经大于剩余未搜索的木棍的总长度,那么就可以直接返回false。
「最小矩形覆盖」问题描述:给定一个平面上的n个点,求一个最小的矩形,使得这n个点都在矩形内部或者矩形的边上。
这个问题也可以使用DFS搜索+剪枝来解决。
具体做法是先枚举矩形的两个相对顶点,然后使用DFS搜索来找到另外两个顶点。
在DFS搜索的过程中,可以使用一些剪枝技巧来提前结束搜索,例如:如果当前搜索到的两个点构成的线段已经包含了所有点,那么就可以直接计算矩形的面积并更新答案。
以上两个例子都是DFS搜索+剪枝的经典应用,可以帮助理解DFS剪枝的思路和技巧。
魔方初级解法(修改)
魔方初级解法(修改)这个魔方初级解法是网上非常流行的"层进"式解法,在很多的网站上都有载。
但是,大多数描述这一解法的通病就是“晦涩难懂”,没想到自己写的也是难逃此劫,呵呵。
重写重写!!第一部分心法1 没有解不出来的魔方,除非这个魔方曾经被拆开而没有正确的装回去。
2 魔方的初级解法像极“背单词”,只要记熟算法即可。
3 解魔方的要义是心静,很多解错的原因是按算法扭的时候一时疏忽。
错了之后,也不要慌,重新来过就是4 如果你不在意速度,随便哪一个魔方就可以玩。
如果你在意,最好去买一个稍好一点的(50~100 rmb)。
一个熟练初级解法的人,一般可以拧进3分钟。
5 熟悉初级解法之后,可以创造性的练习一些高级解法。
最快的高手可以拧进10秒……第二部分解法关键词:“中心” “棱” “顶” “层”每个魔方有6个面。
每个面有9个色块,中间的那一个即为中心色块(“中心”)。
每个面和每个面相交,共有3个色块。
其中中间的一个叫做“棱”,由两个颜色的色块组成。
两头的叫做“顶”,由3个色块组成,是实际上三个面的交点。
如果按照层的角度来看魔方,一个魔方由3层组成。
综上,一个魔方有6个“中心”,12个“棱”,8个“顶”和3层。
层进法就是按照层的顺序,将魔方依次复位的解法。
第一层首先,摆这一层的十字,即四棱分别于四侧面中心色一致)。
任意选择一中心色为顶面(U),可以定出右、左、前(面向你的面)、后和底面这5个面,分别用R、L、F、B和D来表示。
找到欲移动棱(其中有一面色肯定为U面色),将其非U面色调整到相应侧面,然后旋转侧面,归位。
注:这一步相对容易,但是对于初玩魔方的人思维上可能一时没有能够转过来。
所以尽可能的多尝试一下。
第一个棱、第二个棱较为容易。
在调整非U面色到相应侧面时,需要注意,我们通常需要注意两点。
第一,将这个棱尽可能的先移动的D面去。
因为,D面的转动是可以“肆无忌惮”的。
第二,有时,是没有办法把棱调到地面去。
求三角形最大面积
四川省达州市大竹县杨家中学2017—2018学年七年级下册道德与法治期末测试题学校:___________姓名:___________班级:___________考号:___________一、单选题1.当我们遇到很难解决内心矛盾时,除了向家长.老师.亲友寻求帮助外,自己也要学会调节。
下列的做法不正确的是()A.情绪不好时,听一听音乐B.愤怒时,对同学出气C.孤独时,与同学聊天D.紧张时,做深呼吸2.古语说:“劝君莫惜金缕衣,劝君惜取少年时。
”这句话教育我们要()A.珍惜漂亮衣服B.珍惜青春C.珍惜友谊D.珍惜亲情3.下列选项属于自信表现的是()。
A.“某自幼熟读兵书,深知兵法,岂一街亭不能守?!”B.“你能把老师布置的这次全班演讲会组织好吗?”“能!”C.自我评价时,要以人为镜,拿自己的长处跟别人的短处比D.在公共汽车上给老人让座,得到周围人赞许的目光时,感觉很自豪4.自己的好友转学到外地,你会产生的情绪是()A.高兴愉悦B.暴跳如雷C.伤心不已D.惊慌失措5.青春的探索需要( )A.自信B.自卑C.自尊D.独立6.小明想竞选班长,带领大家一同创建良好的班集体。
以下是他的演讲提纲。
其中不恰当的是A.我们要有共同的日标B.我们要各尽所能,发挥所长,奉献集体C.我们班的事务我都会一肩挑,负全责D.我们要团结协作,互助前行7.某班要参加学校的班级网页设计大赛,同学们对此意见不一。
下列态度不正确的是A.我擅长网页设计,可以当“设计师”B.俺啥也不会,让他们看着办吧C.我擅长绘画设计,可以当“美术师”D.我可以为他们搜集资料8.《中华人民共和国未成年人保护法》保护的对象是()A.未满18周岁的中国公民B.年满14周岁、未满18周岁的中国公民C.未满16周岁的中国公民D.年满16周岁、未满18周岁的中国公民9.小昭学习成绩十分优秀,但学校进行优秀学生表彰时,他却榜上无名。
小昭为此十分生气,对班主任和受表彰的同学不理不睬。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
)
下图为在hdoj上的测试结果。 (在不加剪枝的情况下一定会超时,故在此不再测试) 从下往上依次为: 仅剪枝1 剪枝1+剪枝2 剪枝1+剪枝2+剪枝3
可以发现,加上剪枝2,和仅剪枝1相比,用时减少约60%(预计有 判断魔方有几个面的运算的影响)。同时,在剪枝1+剪枝2的基础上, 再加上剪枝3,还能加快约0.9秒(这取决于数据)。
综上,一共12种基本操作。 考虑一下运算次数:12^7*24=859963392,约8.5亿,也就是说,处 理一个魔方最坏需要基本运算8.5亿个,这是不可接受的,所以需要考虑剪 枝。
计算对应关系
以下约定: 1)前面指 6 、 7 、 12 、 13 这一面,左面 指 4 、 5 、 10 、 11 这一面,上面指 0 、 1 、 2、3这一面。 2)a→b表示原来在a位置的数旋转后移 动到b位置 前面的旋转中顺时针旋转对应关系:
剪枝的原则
1.正确性:必须保证不丢失正确的结果。
2.准确性:能够尽可能多的减去不能通向正解的枝条 3.高效性:在很多时候,为了加强优化的效果,我们 会增加一些判断,这样对程序效率也带来了副作用, 所以要考虑剪枝的高效性,否则得不偿失。
剪枝的分类
1.最优性剪枝
又称为上下界剪枝 .我们可以回想一下 ,平时在做一些要求最优解 的问题时,搜索到一个解,是不是把这个解保存起来,若下次搜索到的解
3、剪枝第二次
注意到在题目要求中提到: 在N步操作以内(包括N步)最多能使几个面的4个块的颜色相同。 也就是说,可以 0步,可以 1步,可以 2步,只要小于等于 N步即 可,不一定恰好N步。 也就是说,如果进行 DFS ,那么,每次 DFS 都要先对当前魔方状 态进行检查,记录最大4块同色的面数。 换句话说,如果对先顺时针转了上面,在逆时针转了上面,在 这一题中,没有任何意义,还平白无故减少了2次操作。 那这样,我们可以想到,上一次做过A操作,那本次就不应该进 行一个等效于撤销 A操作的操作。而对上述 6个操作中的每一个,有 且仅有1个操作与此操作作用刚好相互抵消, 也就是,第一次旋转有6种选择,之后每次旋转有5种选择。 那 这 样 , 极 限 情 况 下 , 需 要 的 基 本 运 算 次 数 为 6*(5^6)*24= 2250000,相比第一次剪枝,理论上时间减少了约2/3.
一些死胡同。如果我们能够在刚刚进入这样的死胡同的时候,就能够
判断出来并立即剪枝,程序的效率往往会得到提高。而所谓可行性剪 枝,正是基于这样一种考虑。
#include <stdio.h> const int front[24]={0,1,8,14,4,3,7,13,17,9 ,10,2,6,12,16,15,5,11,18,19,20,21,22,23}; const int up[24]={1,3,0,2,23,22,4,5,6,7,10, 11,12,13,14,15,16,17,18,19,20,21,9,8}; const int left[24]={6,1,12,3,5,11,16,7,8,9, 4,10,18,13,14,15,20,17,22,19,0,21,2,23}; int n,maxnum; int current[12][24]; void turnup(int depth) { for(int i=0;i<24;i++) current[depth][i]=current[depth1][up[i]]; } void turnleft(int depth) { for(int i=0;i<24;i++) current[depth][i]=current[depth1][left[i]]; }
比这个解更优,就又把更优解保存起来?其实这个较优解在算法中被称
为“下界”,与此类似还有“上界”.在搜索中,如果已判断出这一分支 的所有子节点都低于下界,或者高于上界,我们就可以将它剪枝.
2.可行性剪枝
搜索过程可以看作是对一棵树的遍历。在很多情况下,并不是搜 索树中的所有枝条都能通向我们需要的结果,很多的枝条实际上只是
void turnfront(int depth) { for(int i=0;i<24;i++) current[depth][i]=current[depth -1][front[i]]; } void dfs(int depth,int pre); int main() { while(scanf("%d",&n)!=EOF) { for(int i=0;i<24;i++) scanf("%d",¤t[0][i]); maxnum=0; dfs(1,0); printf("%d\n",maxnum); } return 0; }
(1)前面旋转对应关系:
const int front[24]={0,1,8,14,4,3,7,13,17, 9,10,2,6,12,16,15,5,11,18,19,20,21,22,23};
(2)上面旋转对应关系:
const int up[24]={1,3,0,2,23,22,4,5,6,7, 10,11,12,13,14,15,16,17,18,19,20,21,9,8};
搜索(剪枝&打表)
一、问题描述
给了一个2*2的魔方,每步操作可以 ( HDU4801 ) 将任意一面翻转90度,现在问在 N(<=7)步内,最多能翻出几面相同 的。
Pocket Cube
二、解题思路
1、最朴素的实现
首先可以发现,极限情况下,最多旋转7次,次数很小,可以考虑用穷举, 或者说,DFS的方法来实现。其次考虑,对当前的魔方状态,有多少种单 次转动的行为可以 转成另一种状态:
需要的运算次数:6^7*24=6718464,只需要6百万的基本运算,需要的 基本运算是剪枝前的1/128,理论上效果极佳.。
具体实现
减少代码量
首先可以预见,对每一种旋转方法,我们需要写出这种旋转方 法操作后某个位置的色块移动到的区域。换言之,我们需要预先计 算出 6 种对应关系,对每种对应关系写出相应的表示旋转操作的数 组——需要6个24个元素的一维数组。24*6=144,要写的量比较大, 非常容易出错。 可以注意到,逆时针旋转1次等效于顺时针旋转3次 也就是说,具体实现中,可以只预先计算顺时针旋转的3个操作 的对应关系,在实现逆时针旋转的时候,用3次顺时针旋转来替代。 (当然也可以先算好逆时针实现,顺时针旋转时调用3次逆时针旋转)
4、剪枝第三次
其实上述两次剪枝的优化效果已经非常好了,但是我们还可以考 虑再追求极致一下。 当某一次旋转之后6个面的4个小块的颜色都相同的时候,这个魔 方已经还原,不可能再有更多面同色了,也就是说,答案确定是6了, 不需要再进行枚举旋转操作了。 理论上这个剪枝能有一定的优化效果,但效果很有限。
//第三次剪枝 //如果已经不能再旋转,或者已经有6个面同色,都 不需要再递归了。 if((depth>=n+1)||(maxnum>=6)) return;
if(pre!=3) //第二次剪枝:判断是否做了上次操作的逆操作 { if(pre!=2) turnleft(depth); { turnleft(depth+1); turnup(depth); turnleft(depth+2); dfs(depth+1,1); for(int i=0;i<24;i++) } current[depth][i]=current[depth+2][i]; if(pre!=1) dfs(depth+1,4); { } //先模拟连续逆时针旋转了3次的操作 if(pre!=6) turnup(depth); { turnup(depth+1); turnfront(depth); turnup(depth+2); dfs(depth+1,5); //再把最后结果拿回来,当做顺时针旋转1次的操作 } for(int i=0;i<24;i++) if(pre!=5) current[depth][i]=current[depth+2][i]; { dfs(depth+1,2); turnfront(depth); } turnfront(depth+1); if(pre!=4) turnfront(depth+2); { for(int i=0;i<24;i++) turnleft(depth); current[depth][i]=current[depth+2][i]; dfs(depth+1,3); dfs(depth+1,6); } }
//剪枝第一次 // 12种基本操作中有6对操作两两等效 //逆时针旋转1次等效于顺时针旋转3次 int current[12][24]; void turnup(int depth) { for(int i=0;i<24;i++) current[depth][i]=current[depth-1][up[i]]; //根据up对应关系 } void turnleft(int depth) { for(int i=0;i<24;i++) current[depth][i]=current[depth-1][left[i]]; } void turnfront(int depth) { for(int i=0;i<24;i++) current[depth][i]=current[depth-1][front[i]]; }
//depth表示正在做第几次旋转,pre表示上一次操作做了哪一种旋转 void dfs(int depth,int pre) { //先检查前一次旋转之后有多少个面4块同色 int tempnum=0; if((current[depth-1][0]==current[depth1][1])&&(current[depth-1][1]==current[depth1][2])&&(current[depth-1][2]==current[depth1][3]))tempnum++; if((current[depth-1][6]==current[depth1][7])&&(current[depth-1][7]==current[depth1][12])&&(current[depth-1][12]==current[depth1][13]))tempnum++; if((current[depth-1][16]==current[depth1][17])&&(current[depth-1][17]==current[depth1][18])&&(current[depth-1][18]==current[depth1][19]))tempnum++; if((current[depth-1][20]==current[depth1][21])&&(current[depth-1][21]==current[depth1][22])&&(current[depth-1][22]==current[depth1][23]))tempnum++; if((current[depth-1][4]==current[depth1][5])&&(current[depth-1][5]==current[depth1][11])&&(current[depth-1][11]==current[depth1][10]))tempnum++; if((current[depth-1][8]==current[depth1][9])&&(current[depth-1][9]==current[depth1][15])&&(current[depth-1][15]==current[depth1][14]))tempnum++; //如果有更多面同色则更新 if(tempnum>maxnum) maxnum=tempnum; //第三次剪枝 //如果已经不能再旋转,或者已经有6个面同色,都不需要再递归 了。 if((depth>=n+1)||(maxnum>=6)) return;(3)左面旋转对应关系: