这一节我们回顾一下我们之前学的DFS、BFS。
它们是暴力法的直接实现,能把所有可能的状态都搜出来,然后从中找到解。
不过,暴力法往往比较低效,把时间浪费在很多不必要的计算上。比如BFS 中的“跳蚱蜢”问题,从一个状态继续下一跳,有 4 种跳法,但是其中一些状态是不用跳的,因为是重复的。
在这个问题中,我们用了判重技术,它删去了这些不必要的跳法。判重极大地减少了计算量,它是剪枝技术的一种。
剪枝是一个比喻:把不会产生答案的,或不必要的枝条“剪掉”。而剪枝的关键在于剪枝的判断:剪什么枝、在哪里减。剪枝是搜索常用的优化手段,常常能把指数级的复杂度,优化到近似多项式的复杂度。
可行性剪枝:对当前状态进行检查,如果当前条件不合法就不再继续,直接返回
搜索顺序剪枝:搜索树有多个层次和分支,不同的搜索顺序会产生不同的搜索树形态,复杂度也相差很大。
最优性剪枝:在最优化问题的搜索过程中,如果当前花费的代价已超过前面搜索到的最优解,那么本次搜索已经没有继续进行下去的意义,此时停止对当前分支的搜索进行回溯。
排除等效冗余:搜索的不同分支,最后的结果是一样的,那么只搜一个分支就够了。
记忆化搜索:在递归的过程中,有许多分支被反复计算,会大大降低算法的执行效率。用记忆化搜索,将已经计算出来的结果保存起来,以后需要用到的时候直接取出结果,避免重复运算,从而提高了算法的效率。记忆化搜索一般在DP中讲解。
一个题目中可以用到多种剪枝技术。
不过,这么多剪枝技术,也用不着记,总思路就是:减少搜索状态。说一千道一万,归根结底一句话:“搜索必剪枝、无剪枝不搜索”。如果你回顾前2节的BFS、DFS例题,可以发现,每一题都或多或少用到了剪枝。
接下来让我们回顾一下DFS 和 BFS 例题,看用了什么剪枝技术。
题目名称:迷宫 链接:https://blog.csdn.net/m0_51951121/article/details/122990741?spm=1001.2014.3001.5501题目大意:迷宫内每个点都有一个人,问多少人能走出来。 剪枝:记忆化搜索,如果一个点搜过,就不用再搜。
题目名称:全球变暖 链接:https://blog.csdn.net/m0_51951121/article/details/123300818?spm=1001.2014.3001.5501题目大意:有多少个岛被淹没。 剪枝:记忆化搜索,被检查过的点不用再检查。
题目名称:跳蚱蜢 链接:https://blog.csdn.net/m0_51951121/article/details/123316286?spm=1001.2014.3001.5501 题目大意:从一种状态跳到另一种状态,要多少步。 剪枝:判重。
题目名称:迷宫 链接:https://blog.csdn.net/m0_51951121/article/details/123300818?spm=1001.2014.3001.5501 题目大意:找到最短路径。 剪枝:最优性剪枝,找字典序最短的路。
不知不觉中已经用了这么多剪枝技巧。
下面我们再来一个题了解一下剪枝。
如下图所示,3×3 的格子中填写了一些整数。
我们沿着图中的红色线剪开,得到两个部分,每个部分的数字和都是 60。
本题的要求就是请你编程判定:对给定的 m×n 的格子中的整数,是否可以分割为两个部分,使得这两个区域的数字和相等。
如果存在多种解答,请输出包含左上角格子的那个区域包含的格子的最小数目。
如果无法分割,则输出 0。
程序先读入两个整数m,n 用空格分割 (m,n<10),表示表格的宽度和高度。
接下来是 n 行,每行 m 个正整数,用空格分开。每个整数不大于 104。
在所有解中,包含左上角的分割区可能包含的最小的格子数目。
3 3 10 1 52 20 30 1 1 2 3
3
def dfs(x,y,c,s): global ans dir = [[1,0],[0,-1],[0,1],[-1,0]] if 2*s>summ: return if 2*s==summ: if vis[0][0]: ans = c return vis[x][y] = 1 for k in range(4): tx = x+dir[k][0] ty = y +dir[k][1] if tx>=0 and tx<n and ty>=0 and ty<m and not vis[tx][ty]: dfs(tx,ty,c+1,s+wzy[x][y]) vis[x][y] = 0 m,n = map(int,input().split()) vis = [ [0,0,0,0,0,0,0,0,0] for _ in range(9)] wzy = [] summ = 0 for i in range(n): wzy.append(list(map(int,input().split()))) for k in range(m): summ += wzy[i][k] dfs(0,0,0,0) print(ans)