浅谈搜索算法在信息学竞赛中的应用.docx

上传人:b****4 文档编号:5414275 上传时间:2022-12-16 格式:DOCX 页数:8 大小:36.60KB
下载 相关 举报
浅谈搜索算法在信息学竞赛中的应用.docx_第1页
第1页 / 共8页
浅谈搜索算法在信息学竞赛中的应用.docx_第2页
第2页 / 共8页
浅谈搜索算法在信息学竞赛中的应用.docx_第3页
第3页 / 共8页
浅谈搜索算法在信息学竞赛中的应用.docx_第4页
第4页 / 共8页
浅谈搜索算法在信息学竞赛中的应用.docx_第5页
第5页 / 共8页
点击查看更多>>
下载资源
资源描述

浅谈搜索算法在信息学竞赛中的应用.docx

《浅谈搜索算法在信息学竞赛中的应用.docx》由会员分享,可在线阅读,更多相关《浅谈搜索算法在信息学竞赛中的应用.docx(8页珍藏版)》请在冰豆网上搜索。

浅谈搜索算法在信息学竞赛中的应用.docx

浅谈搜索算法在信息学竞赛中的应用

浅谈搜索算法在信息学竞赛中的应用

SearchAlgorithminInformatics

【前言】

在信息学竞赛日渐普及,信息技术越来越重要的今天,搜索算法,一种充分利用计

算机计算速度遍历所有可能解的算法,被认为非常基础也非常重要。

让我们走近这听起

来非常高端的算法,一窥其真面目。

【摘要】

本文对搜索算法的两个分支——深度优先搜索(dfs)和广度优先搜索(bfs)展开

了研究,并通过在例题中的各种应用分析两种搜索方法的优化,对这一类的算法进行了

通用总结。

【关键词】

搜索算法信息学深度优先搜索广度优先搜索DFSBFS剪枝

 

【研究过程】

主要算法

(1)深度优先搜索(dfs)

深度优先搜索属于图算法的一种,英文缩写为DFS即DepthFirstSearch.其过程简要来说是对每一个可能的分支路径深入到不能再深入为止,而且每个节点只能访问一次。

主要用于图的搜索,但是在许多别的领域也有广泛应用。

举例说明之:

下图是一个无向图,如果我们从A点发起深度优先搜索(以下的访问次序并不是唯一的,第二个点既可以是B也可以是C,D),则我们可能得到如下的一个访问过程:

A->B->E(没有路了!

回溯到A)->C->F->H->G->D(没有路,最终回溯到A,A也没有未访问的相邻节点,本次搜索结束).

让我们先看一道经典例题。

【深度搜索基础】迷宫路径(深搜)

Description

  这是实验心理学中的一个经典问题,心理学家把一只老鼠从一个无顶盖的大盒子的入口处赶进迷宫。

迷宫中设置很多隔壁,对前进方向形成了多处障碍,心理学家在迷宫的唯一出口处放置了一块奶酪,吸引老鼠在迷宫中寻找通路以到达出口。

  迷宫以一个01矩阵表示,0表示通路,1表示不通,入口在座标(1,1),出口在(m,n),m表示行,n表示列。

老鼠在某一格子时,可以向周围8个格子移动(只要目的格子不为1或没有超出边界)。

现求解出到达出口的最少移动步数,注:

站在(m,n)即表示已经抵达出口,起始时老鼠站在(1,1)处。

这道题的基本思路是以(1,1)即起点为起始点,不断地通过递归来拓展每一个可能节点,直到找到终点或无路可走为止。

在遍历所有可能路径的同时统计最短的一条路,输出答案即可。

实际c++代码如下:

∙#include

∙#include

∙usingnamespacestd;

∙intg[52][52],n,m,xmin=10000;

∙struct{

∙intx;

∙inty;

∙}xx[8];

∙voidx(intnn,intmm,intc);

∙main()

∙{

∙ints,ss;

∙xx[0].x=0;xx[0].y=1;xx[1].x=1;xx[1].y=1;

∙xx[2].x=1;xx[2].y=0;xx[3].x=1;xx[3].y=-1;

∙xx[4].x=0;xx[4].y=-1;xx[5].x=-1;xx[5].y=-1;

∙xx[6].x=-1;xx[6].y=0;xx[7].x=-1;xx[7].y=1;

∙cin>>n>>m;

∙for(s=0;s<=n+1;s++){g[s][0]=1;g[s][m+1]=1;}

∙for(s=0;s<=m+1;s++){g[0][s]=1;g[n+1][s]=1;}

∙for(s=1;s<=n;s++)

∙for(ss=1;ss<=m;ss++)

∙cin>>g[s][ss];

∙x(1,1,0);

∙if(xmin==10000)cout<<"no";

∙elsecout<

∙}

∙voidx(intnn,intmm,intc)

∙{

∙ints;

∙if((nn==n&&mm==m)&&(c

∙xmin=c;

∙}

∙elseif(c

∙for(s=0;s<=7;s++){

∙if(g[nn+xx[s].x][mm+xx[s].y]==0){

∙g[nn+xx[s].x][mm+xx[s].y]=2;

∙x(nn+xx[s].x,mm+xx[s].y,c+1);

∙g[nn+xx[s].x][mm+xx[s].y]=0;

∙}

∙}

∙}

这段代码中应用了标志数组的小技巧,使程序更加简洁明了。

同时,我们可以发现这种算法在最不利情况下的时间效率其实非常低,所以在这里加了非常有效的可行性剪枝,使效率大大提高。

关于一些剪枝方法,我会在后文谈到。

(2)广度优先搜索(bfs)

宽度优先搜索算法(又称广度优先搜索)是最简便的图的搜索算法之一,这一算法也是很多重要的图的算法的原型。

Dijkstra单源最短路径算法和Prim最小生成树算法都采用了和宽度优先搜索类似的思想。

其别名又叫BFS,属于一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。

换句话说,它并不考虑结果的可能位置,彻底地搜索整张图,直到找到结果为止。

在bfs中,通常使用先进先出队列(一种数据结构)来维护,并通过判重使搜索规模得到控制,避免做无用功,重复搜索同样的状态。

如图所示:

以1为起点,8为终点,路径长度为1。

在图中,我们可以通过路径段数把整个图划分成三层,其中,2,3,4是由1直接拓展出的节点,先把他们加入队列。

接下来取出2,通过2拓展出5,6两个节点并加入队列。

下一步取出3,通过3拓展出6,7。

需要注意的是,此时6已经在队列中了,所以不需要再次入队,以后如果再遇到6也不需要入队,而且该情况仅对路径长度为1时适用。

依此类推,当取出的节点为终点时就可以结束搜索了。

我们再来看看例题。

【宽度搜索基础】奇怪的电梯(宽搜)

Description

  呵呵,有一天我做了一个梦,梦见了一种很奇怪的电梯。

大楼的每一层楼都可以停电梯,而且第i层楼(1<=i<=N)上有一个数字Ki(0<=Ki<=N)。

电梯只有四个按钮:

开,关,上,下。

上下的层数等于当前楼层上的那个数字。

当然,如果不能满足要求,相应的按钮就会失灵。

例如:

33125代表了Ki(K1=3,K2=3,……),从一楼开始。

在一楼,按“上”可以到4楼,按“下”是不起作用的,因为没有-2楼。

那么,从A楼到B楼至少要按几次按钮呢?

这道题的思路和上面的最短路径其实有异曲同工之妙。

按一次按钮相当于走过路径长度为一的路,到达的每层楼则相当于上图中的节点,但是哪两条节点间有通路呢?

这就要看每层楼上的Ki值了,如果某层楼楼层数+/-Ki=另一楼层数,那么这两个节点间就有长度为1的边相连。

具体代码如下:

∙#include

∙#include

∙usingnamespacestd;

∙voidlift(intx,intc,intz);

∙intg[100],N,A,B,front,rear,step[201],ss=0;

∙boolboo[201],arrive=false;

∙intki[201];

∙intmain()

∙{

∙ints;

∙memset(boo,true,sizeof(boo));

∙cin>>N>>A>>B;

∙for(s=1;s<=N;s++)cin>>ki[s];

∙if(A!

=B){

∙boo[A]=false;

∙g[0]=A;

∙front=0;

∙step[g[front]]=0;

∙rear=1;

∙while(front!

=rear){

∙lift(g[front],step[g[front]],1);

∙lift(g[front],step[g[front]],2);

∙if(arrive)break;

∙front++;

∙front=front%100;

∙}

∙if(ss==0)cout<<-1<

∙elsecout<

∙}

∙elsecout<<0<

∙return0;

∙}

∙voidlift(intx,intc,intz)

∙{

∙if(z==1){

∙x=x+ki[g[front]];

∙if(boo[x]&&(x>0)&&(x<=N)){

∙boo[x]=false;

∙step[x]=c+1;

∙g[rear]=x;

∙rear++;

∙rear=rear%100;

∙}

∙if(x==B){arrive=true;ss=step[x];}

∙}

∙else{

∙x=x-ki[g[front]];

∙if(boo[x]&&(x>0)&&(x<=N)){

∙boo[x]=false;

∙step[x]=c+1;

∙g[rear]=x;

∙rear++;

∙rear=rear%100;

∙}

∙if(x==B){arrive=true;ss=step[x];}

∙}

∙}

1、优化方法:

剪枝

(一)剪枝的原则

原则之一:

正确性。

   

因为它能够“剪去”搜索树中的一些“枝条”。

然而,如果在剪枝的时候,将“长有”我们所需要的解的枝条也剪掉了,那么,一切优化也就都失去了意义。

所以,对剪枝的第一个要求就是正确性,即必须保证不丢失正确的结果,这是剪枝优化的前提。

我们利用“必要条件”来进行剪枝判断。

也就是说,通过解所必须具备的特征、必须满足的条件等方面来考察待判断的枝条能否被剪枝。

这样,就可以保证所剪掉的枝条一定不是正解所在的枝条。

原则之二:

准确性。

即能够尽可能多的剪去不能通向正解的枝条。

准确性可以说是剪枝优化的生命。

原则之三:

高效性。

 经常还需要提高判断操作本身的时间效率。

 综上所述,我们可以把剪枝优化的主要原则归结为六个字:

正确、准确、高效。

(二)剪枝方法

1、可行性剪枝

搜索过程可以看作是对一棵树的遍历。

在很多情况下,并不是搜索树中

的所有枝条都能通向我们需要的结果,很多的枝条实际上只是一些死胡同。

如果我们能够在刚刚进入这样的死胡同的时候,就能够判断出来并立即剪

枝,程序的效率往往会得到提高。

而所谓可行性剪枝,正是基于这样一种考

虑。

2、最优性剪枝

在我们平时遇到的问题中,有一大类是所谓最优化问题,即所要求的结果是最优解。

此时就可以利用最优性剪枝来简化搜索复杂度。

   在搜索的过程中,一般情况下,我们需要保存一个“当前最优解”,实际上就是保存解的优度的一个下界。

在遍历到搜索树的叶子节点的时候,我们就能得到一个新的解,当然也就得到了它的评价函数值,如果新解更优则更新优值下限。

搜索结束后,所保存的解就是最优解。

 那么,最优性剪枝又是如何进行的呢?

当我们处在搜索树的枝条上时,可以通过某种方法估算出该枝条上的所有解的评价函数的上界,即所谓估价函数。

显然,大于当前保存的优度的下界,是该枝条上存在最优解的必要条件,否则就一定可以剪枝。

所以,最优性剪枝也可以称为“上下界剪枝”。

同时,我们也可以看到,最优性剪枝的核心问题就是估价函数的建立。

对这种剪枝方法应用最典型的就是A*算法,其效率很大程度上由估价函数的优劣左右,所以建立有效的估价函数也是程序取得高效率的重点。

【研究结论】

搜索在信息学奥赛中是非常有效的算法,当我们真正利用好各种优化方法时,搜索的效率能够大大提升,帮助我们解决许多难题。

我们不应该轻视基础的搜索算法,而是应该认真地把搜索吃透。

对于生活中许多其他问题也是一样,对待基础知识的正确方法是认真弄懂,踏踏实实地前进,这种思想将会对我们起巨大的帮助。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 解决方案 > 学习计划

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1