Sweety

Practice makes perfect

导航

杭电 rescue(经典广搜)(深搜广搜对比)

Posted on 2015-02-07 23:03  蓝空  阅读(310)  评论(0编辑  收藏  举报

今天也终于领略到什么是深搜什么是广搜的区别和特点了,其实一直不太懂什么时候用深搜,什么时候用广搜,虽然两种都有用过,但是都是结合解题报告或者其他途径来做的,总感觉深搜用起来比较顺手,感觉很多题都可以用深搜来解决,但是今天遇到的这个题用深搜怎么想方设法都不好用,结果应该正确,但是就是TimeLimit,只好用广搜来解了,也颇费周折的各方面查资料知道了广搜一般用在有这样的提示:最短时间或者最短路径,或许这就是基本层面但很有用处的区别,现在的理解就到这里了,另外其他学术性的区别见博客:http://blog.csdn.net/u014665013/article/details/39558093


声明一下:优先队列和队列的区别,优先队列是能通过优先级来限定队列的顺序的,但是队列只能是先进先出,不能按照参数来限定顺序 ,这里用到的是优先队列


题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=1242

贴一下用深搜做的TimeLimit的代码,毕竟是经过一番思考的...  从四个方向深搜..

#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <iostream>
using namespace std;
int sum=0, row,line,doorrow,doorline,startrow,startline,count=0,mark=0;
char ch[205][205]={0};
void find(int i,int j){
	if(doorrow==i&&doorline==j){ //注意最后一次到达的时候会将a还原时改为'.' ,但是不妨碍  
	   if (mark==0||sum<count) {
	    mark=1;
	    count=sum; 
		}
	} 
	else {
	   if(i>0&&ch[i-1][j]!='#'){
	   	char temp='.';
	   	sum++;
	    if(ch[i-1][j]=='x')  sum++,temp='#';//如果是守卫,需要用1单位时间来杀掉他 
	    ch[i-1][j]='#';
	    find(i-1,j);
	    if(temp=='#') sum--,ch[i-1][j]='x'; 
	    else  ch[i-1][j]='.';
	    sum--;
	   }
   	  if(i<row-1&&ch[i+1][j]!='#'){
   	  	char temp='.';
		sum++;
		if(ch[i+1][j]=='x')  sum++,temp='#';
		ch[i+1][j]='#';
	    find(i+1,j);
	    if(temp=='#') sum--,ch[i+1][j]='x'; 
	    else ch[i+1][j]='.';
	    sum--;
	    }
   	  if(j>0&&ch[i][j-1]!='#'){
   	   char temp='.';
	   sum++;
	   if(ch[i][j-1]=='x')  sum++,temp='#';
	   ch[i][j-1]='#';
	   find(i,j-1);
	   if(temp=='#') sum--,ch[i][j-1]='x'; 
	   else ch[i][j-1]='.';
	   sum--;
   	  }
   	 if(j<line-1>0&&ch[i][j+1]!='#'){
   	 	char temp='.';
		sum++;
		if(ch[i][j+1]=='x')  sum++,temp='#';
		ch[i][j+1]='#';
		find(i,j+1);
		if(temp=='#') sum--,ch[i][j+1]='x'; 
	    else ch[i][j+1]='.';
		sum--;
   	  }
    }
}
int main (){
	while(~scanf("%d%d",&row,&line)){
	sum=0,mark=0,count=0;	//别忘了每次都要初始化 
	for(int i=0;i<row;i++)
	   scanf("%s",ch[i]);
	for(int i=0;i<row;i++) 
	for(int j=0;j<line;j++){
	if(ch[i][j]=='a')
	   	doorrow=i,doorline=j;
	if(ch[i][j]=='r')
	    startrow=i,startline=j;	
	} 
	find(startrow,startline);
	if(count==0)
	printf("Poor ANGEL has to stay in the prison all his life.\n"); 
	else
	 printf("%d\n",count); 
	}
  return 0;
}

使用广搜(使用优先级队列,因为两者好像不可分的),通过优先级队列的排序功能控制逐层进行遍历。

这里又悟出了深搜和广搜的一点不同:

现在知道为什么用宽度搜索了,(1)如果深度搜索的话,会沿着一条路径走到头,包括中间有很多分叉路,这样只有走到头才会停止本次搜索,但是宽度搜索就不一样了,他会按照层数进行查找,这样可以使一些不正确的路径不会走到头,相当于节省了这部分时间,所以相对来书效率就高了。

(2)另外深搜和广搜另外一个很大的不同好像也在于,深搜一般是递归调用函数,这样深搜;但是广搜则是没有递归调用函数,而是通过优先队列来通过循环实现的,这应该也是一个很大的不同吧

广搜代码:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <queue>
#define N 201
using namespace std;
//优先队列解决,广度优先
struct Persion
{
    int x,y;
    int times;
    friend bool operator < (const Persion &a,const Persion &b)
    {
        return a.times>b.times; //">" 返回队列中较小的元素;"< " 则返回队列中较大的元素
    }
};
//这样优先级排序为小的在top(可以理解为右面是top) 
int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};//四个方向的操作 
char map[N][N];
int visited[N][N];
int m,n;
int BFS(int x,int y)
{
    priority_queue <Persion> q; //新建优先队列 
    Persion current,next;
    
    memset(visited,0,sizeof(visited));
    
    current.x=x,current.y=y,current.times=0;
    
    visited[current.x][current.y]=1;//标记访问过了 
    q.push(current);    //当前访问的入队 
    while(!q.empty())
    {
      current=q.top();
      q.pop();    // 
      for(int i=0;i<4;i++)//对四个方向查找 
      {
         next.x=current.x+dir[i][0];
         next.y=current.y+dir[i][1];
         if( next.x>=0&&next.x<n  &&   next.y>=0&&next.y<m   &&    map[next.x][next.y]!='#'   &&    !visited[next.x][next.y])
         {
            if(map[next.x][next.y]=='a')
                return current.times+1;
            if(map[next.x][next.y]=='x')
              next.times=current.times+2;
            else
              next.times=current.times+1;
            visited[next.x][next.y]=1;
            q.push(next);
        }
      }
    }
    return -1;
}
int main()
{
    int i,j;
    Persion angle;
    while(cin>>n>>m&&(m||n))
    {
    for(i=0;i<n;i++)
        for(j=0;j<m;j++)
        {
           cin>>map[i][j];
           if(map[i][j]=='r')
           angle.x=i,angle.y=j;
        }
    int times=BFS(angle.x,angle.y);
    if(times==-1)
       cout<<"Poor ANGEL has to stay in the prison all his life."<<endl;
    else
      cout<<times<<endl;
    }
    return 0;
}