Java教程

蓝桥杯精选算法赛题——剪枝——剪格子

本文主要是介绍蓝桥杯精选算法赛题——剪枝——剪格子,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

这一节我们回顾一下我们之前学的DFS、BFS。
它们是暴力法的直接实现,能把所有可能的状态都搜出来,然后从中找到解。
不过,暴力法往往比较低效,把时间浪费在很多不必要的计算上。比如BFS 中的“跳蚱蜢”问题,从一个状态继续下一跳,有 4 种跳法,但是其中一些状态是不用跳的,因为是重复的。
在这个问题中,我们用了判重技术,它删去了这些不必要的跳法。判重极大地减少了计算量,它是剪枝技术的一种
剪枝是一个比喻:把不会产生答案的,或不必要的枝条“剪掉”。而剪枝的关键在于剪枝的判断:剪什么枝、在哪里减。剪枝是搜索常用的优化手段,常常能把指数级的复杂度,优化到近似多项式的复杂度。

  1. BFS的主要剪枝技术是判重,如果搜索到某一层时,出现重复的状态,就剪枝。
  2. DFS的剪枝技术较多,有可行性剪枝、最优性剪枝、搜索顺序剪枝、排除等效冗余、记忆化搜索等等:

可行性剪枝:对当前状态进行检查,如果当前条件不合法就不再继续,直接返回
搜索顺序剪枝:搜索树有多个层次和分支,不同的搜索顺序会产生不同的搜索树形态,复杂度也相差很大。
最优性剪枝:在最优化问题的搜索过程中,如果当前花费的代价已超过前面搜索到的最优解,那么本次搜索已经没有继续进行下去的意义,此时停止对当前分支的搜索进行回溯。
排除等效冗余:搜索的不同分支,最后的结果是一样的,那么只搜一个分支就够了。
记忆化搜索:在递归的过程中,有许多分支被反复计算,会大大降低算法的执行效率。用记忆化搜索,将已经计算出来的结果保存起来,以后需要用到的时候直接取出结果,避免重复运算,从而提高了算法的效率。记忆化搜索一般在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)

这篇关于蓝桥杯精选算法赛题——剪枝——剪格子的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!