zoukankan      html  css  js  c++  java
  • 2017.8.8搜索课总结

    1.有2 个没有刻度的杯子, 容积分别是V1、V2, 另有一个无限大
    的水缸, 里面有无限多水。对这两个杯子可以进行如下操作:
    1. 从水缸里往一个杯子加满水;
    2. 把一个杯子里的水全部倒进水缸;
    3. 从一个杯子往另一个杯子里倒水, 直到另一个杯子满
    或一个杯子空为止。
    现在我们需要通过一定顺序的操作, 使杯子1、杯子2或杯子
    1+ 杯子2 中的水的体积是V3。
    0 < V1, V2 < 2^7; 0 < V3 < 2^8

    分析:这个直接bfs就行了,不过需要先处理一下,即我们先把v1,v2,v3的最大公约数给除掉,避免数据过大.

    2.在古埃及, 人们使用单位分数的和(形如1/a 的, a 是自然数)
    表示一切有理数。如:2/3=1/2+1/6, 但不允许2/3=1/3+1/3,
    因为加数中有相同的。
    • 对于一个分数a/b, 表示方法有很多种, 但是哪种最好呢?
    • 首先, 加数少的比加数多的好, 其次, 加数个数相同的,最小
    的分数越大越好。如19/45 分解成1/5+1/6+1/18 是最好的。
    • 计算最好的表达方式。

    分析:直接深搜是不行的,因为它不能保证分数使用的最少,直接宽搜也不行,因为可能会扩展出很多分数,很难保存记录下来。那么就要用到迭代加深搜索:规定一个搜索的上限,然后用dfs,如果搜到当前的上限满足要求,直接输出上限即可,这样既不会浪费过多内存也可以确保是最少的分数.不过这个算法缺点还是有的,我们每增加上限,以前搜过的就要重新搜,所以迭代加深搜索是dfs和bfs都不行时的救命稻草.当然,用IDA*也是可以的.

    能用bfs或dfs时不要用.

    3.地球上的科学家收到了来自外星的信号:
    000023*000011=002093,科学家猜想这是某个外星人的
    年龄。但有人指出,这些外星人好像不怎么聪明,因为
    23*11=253,而非2093。但是科学家们发现,如果把
    000011改成00091的话算式就成立了。他们认为这是接收
    信号的时候出了差错的缘故。
    • 现在给你这样一个算式,问最少改动几个数字就能使得算
    式成立?(格式是??????*??????=??????,忽略进位)

    分析:如果直接每一位枚举,要搜索10^18次,直接T啊,但是我们可以不用搜这么多位,为什么呢?我们搜乘数,然后就可以直接算出乘积,看题目给出的乘积有多少位与我们算出来的不一样的。

         这样的话还是会T,还需要剪枝,其实和noip靶形数独那道题差不多,改变一下搜索顺序就可以了,

    能这样做因为这只要求给出一个答案,给出所有答案就gg了,如果要说原理的话我们可以结合靶形数独,填数独一般就是从能填最少的数的位置上填,所以这样做可以“骗”得更高分,做乘法我们一般从个位开始乘,因为乘积的个位只取决于乘数的个位,然后我们可以很快确定十位,百位,千位......

    4.用关系“<”和“=”将3 个数A、B和C依序排列时有13 种
    不同的序关系: A=B=C,A=B<C,A<B=C,A<B<C,
    A<C<B,A=C<B,B<A=C,B<A<C,B<C<A, B=C<A,
    C<A=B,C<A<B,C<B<A。
    • 将n 个数(1 <= n <=10)依序排列时有多少种序关系。

    分析:其实可以想到枚举字母和符号,但是这样枚举的信息实在是太多了,直接T,但是可以观察样例中第三个,第七个,第十一个,他们其实就是ABC的排列不同,也就是说我们完全可以用数学知识来搞.

         首先考虑完全都是<的情况,只有一种,然后用dp.可以发现如果是等于号连接的,不管怎么样排列都是一样的,所以我们只需要考虑组合数!(不需要考虑顺序),然后枚举符号,其实只需要强制枚举等于号的数量即可,我们强制用k个等于号,剩下的n-k个数无所谓什么符号,这样就可以用dp解决:
    f(n) = ΣC(n,k)*f(n-k)  (1 <= k <= n),最后加上1即可.

    5.noip2015斗地主:传送门

    6.一个数字P,告诉你对这个数操作,每次只能乘X 或者
    减Y,请你算算P 变成Q 需要的最小步数。

    分析:可以宽搜,加上剪枝:如果P,Q符号不同,并且X>0,就不要乘了,如果P < Q,就不要减了等等.但是这样还是会有时间上的障碍,因为越往后搜到的状态就越多,呈指数级增长,这个时候我们用双向宽搜解决,从Q到P,乘x就相当于除x,减Y就相当于加Y,具体是怎么实现呢?我们每次找两个方向可以扩展的状态较少的那一方扩展即可。

    7.有n个物品,m块钱,给定每个物品的价格,求买物品的方
    案数。
    • n<=40,m<=10^18

    分析:本来可以用背包解的,可是这个m如此之大,数组都开不下啊,而且这个m绝对不能出现在复杂度中,因为就算logm也难算,况且不可能logm,所以只能出现n,那么做法就是0-1搜索了--看每一个物品到底取不取。然而这个要计算多达2^40次,如果能降到2^20就好了,那么就能想到折半搜索:把一半的数放到一边,另一半的数放在另一边,然后把所有可能的价格保存下来,记左边的为l,那么右边就必须凑齐m-l,然后我们将右边排个序,用二分查找一下上界和下界即可.

    8.考虑一个翻硬币游戏。有N(N<=10000)行硬币,每行9个,
    排成一个N*9的方阵,有的正面朝上有的反面朝上。我们
    每次把一整行或者一整列的所有硬币翻过来,请问怎么翻,
    使得正面朝上的硬币尽量多。

    分析:这是一类染色有伴随状态的问题,就是染色一个会牵连几个的那种,而且所给的方格一定有一个范围特别小,比如这道题的每行9个,这类题目有一个固定的解法,我们先看行和列,枚举较小的列,显然,把一列或一行翻两次是没有任何意义的,那么我们可以只用2^9次枚举每列到底翻不翻,然后得出来的状态再枚举每一行到底翻不翻,如果翻过来正面朝上的硬币比不翻正面朝上的硬币多,就翻,否则就不翻,然后就可以解决这道题.

    9.农夫约翰知道, 聪明的奶牛可以产更多的牛奶。他为奶牛计了一种智
    力游戏, 名叫翻转棋。翻转棋可以分成M *N(1 <=M,N<=15) 个格子,
    每个格子有两种颜色, 一面是黑的, 一面是白的。
    • 一旦翻转某个格子, 这个格子的颜色就会颠倒。如果把所有的格子都
    翻成白的, 就算奶牛赢了。然而, 奶牛的蹄子很大,一旦它们打算翻转
    某个格子, 这个格子附近(即和这个格子有公共边) 的格子也会被翻转。
    一直翻来翻去也很无聊, 奶牛们想最小化必须翻动的次数。
    • 请帮助奶牛确定翻动的最少次数和具体的翻法。如果最小解有多个,
    则输出在字典序意义下最小的那个, 如果不可能完成任务, 则只要输
    出IMPOSSIBLE。

    分析:还是和上题一样的,我们枚举第一行翻哪些,要算2^15次,然后完全可以根据第一行的状态向下推,如果第一行有格子没翻,那么下一行这一列的格子就必须要翻,然后模拟到最后一行看看符不符合要求即可。

    10.给出n根小棒的长度stick[i],已知这n根小棒原本由若干
    根长度相同的长木棒(原棒)分解而来。求出原棒的最
    小可能长度。
    • 9
    • 5 2 1 5 2 1 5 2 1
    • 6

    分析:这是一道比较有意思的搜索题,首先明确搜索的对象,我们不能枚举把哪些木棍拼起来,一是难以实现,二是复杂度高,那么我们完全可以枚举长木棒的长度。但是枚举总要有个范围吧,最大肯定是这些小棒的长度和,最小肯定是这些小棒中最长的那一个,同时要满足长度是小棒和的因数,只有这样才能拆分成正整数段,然后就是添加剪枝的环节了.

         1.如果当前拼成的长度+枚举的小木棍的长度 != 长木棒长,剪枝!

         2.如果一个小木棍用过一次了,后来还有和它相同长度的,并且没有方案可行,就不要搜这个长度的木棍了.

         3.长度从大到小排序.原理:越到后来状态越多

    11.有一个R*C(<=21)的矩阵,每个格子上包含一个0~20的整数。
    求有多少条包含21个格子的路径满足:路径上相邻两个格子
    必须有一条公共边,并且0~20每个数都在路径上出现一次。

    分析:我们可以枚举起点,找终点,这样会T.但是我们可以换一个想法,折半搜索!基本上可以一分为二的搜索都可以用折半搜索来做,具体是怎么做呢?枚举路径的中点,一边扩展10步,另一边扩展10步,每一步都不能走已经出现过的,一旦一端不能走,立即pass掉这个状态.

    12.一个10*10的连连看状态,然后问你最后能不能全部消没。
    (多组数据)

    分析:一开始可以想到枚举消掉哪两个点,然后看能不能,这样判断就好麻烦,更不谈超时的问题。但是,我们可以有另外一种高端的思路:从一个点开始走看能消掉哪些点,然后我们看到底消不消,消哪个,这就是dfs的问题了,至于怎么找消掉的点,很简单,bfs即可.有一个剪枝:如果给定图中有色块是奇数个,那么肯定消不掉.

    13.地图包含一些小方格,每格要么是墙(鬼不能进入)要么是走廊(鬼能进入)。
    • 每一步里,你可以同时移动任意数量的鬼,每个鬼要么待在原地不动,要么移动
    到相邻的格子里(相邻的格子有公共边),如果移动满足下列条件,则移动是可
    行的:
    • 1、 没有一个以上的鬼在同一个格子里;
    • 2、 没有一对鬼在一步里交换了位置。

    问:最少要几步到达最终状态?

    分析:同时枚举多个鬼走的bfs,注意一下判重就好了,优化的话可以用双向bfs.

    14.足柄希望做成体积为Nπ的咖喱,为了做得好看为自己加分,决定把自己
    的咖喱做成蛋糕的形状,并且有M层,每一层都是一个圆柱体,并且每
    一层的半径和高度都要比下面的那一层要小。
    但是做成,需要很多黄金比例辛香料洒在咖喱的表层,为了不麻烦间宫
    小姐,足柄希望做成的蛋糕的表面积Sπ尽可能小。

    分析:半径和高度都是正整数,而且每一层都要严格大于上一层,所以最后一层的高度和r至少要从m枚举.

    那么我们从最后一层开始dfs,加几个最优性剪枝:1.如果当前表面积+切出来的表面积>ans,剪! 2.如果当前体积+最大体积<Nπ,剪!3.如果当前体积+切出来的体积 > ans,剪! 4.h和r都从大到小枚举,因为只要输出一种答案嘛,玄学玄学,这样因为可以搜的状态减少,会降低复杂度.

    15.八数码问题
    将分别标有数字1,2,3,…,8的八块正方形数码牌任意地放
    在一块3×3的数码盘上。放牌时要求不能重叠。于是,在3×3
    的数码盘上出现了一个空格。现在要求按照每次只能将与空格
    相邻的数码牌与空格交换的原则,将任意摆放的数码盘摆成如
    下的状态。
    1 2 3
    4 5 6
    7 8 x

    分析:这道题显然不能用dfs,考虑能否bfs?其实可以,但是保存数据有点困难,但是也是可以做的,方法就是康拓展开!a * 8!+ b * 7! + c * 6! + d * 5! + e * 4! + f * 3!+ g * 2! + h * 1! + i * 0!

    可以证明这个式子是表示的唯一一个局面,具体的就不说了,我们暂且抛弃掉bfs这种解法,可以想到迭代加深搜索,事实上,类似于八数码问题我们都可以用迭代加深搜索解决,因为它既可以清楚地求出最少步数,也可以不用记录那么多状态。

    16.在一个4*4的棋盘上摆放了14颗棋子,其中有7颗白色棋子,7颗黑色棋
    子,有两个空白地带,任何一颗黑白棋子都可以向上下左右四个方向移
    动到相邻的空格,这叫行棋一步, 黑白双方交替走棋,任意一方可以先
    走,如果某个时刻使得任意一种颜色的棋子形成四个一线(包括斜线),
    这样的状态为目标棋局。

    分析:类似八数码问题,我们每次只需要考虑2个空白方块的移动即可.

    17.骑士精神:传送门

    18.引水入城:传送门

    19.靶形数独:传送门

    20.poj1324 这个题暂时还没什么思路,到时候我会补上的

    总结:其实搜索的知识很简单,知道以下几个原则:

         1.要求“最小步数”一类问题可以用bfs,其他的用dfs也能解决

         2.如果搜索树上的某一分支太长,不要考虑dfs

         3.内存过大不要用bfs

         4.如果都不能用就用迭代加深吧

         5.万能优化:启发式搜索估价函数!

    剪枝的话:1.考虑最优化剪枝,一般就是当前解+可能的解要小于ans 2.可行性剪枝,就是看到底能不能搜到答案.

  • 相关阅读:
    (转) tcp的注册端口
    [转] Android中C&C++源码库的初步研究
    (转)vim7.3中文乱码解决方法
    {转} Eclipse 高亮显示选中的相同变量
    libcurl 一个实现了client请求http,ftp的库
    c#操作文件夹
    OutputCache祥解
    非静态的字段、方法或属性“System.Web.UI.Page.ClientScript.get”要求对象引用
    IXMLDOMDocument 成員
    关于中日文和UNICODE之间编码的转换(2008725 15:05:00)
  • 原文地址:https://www.cnblogs.com/zbtrs/p/7309293.html
Copyright © 2011-2022 走看看