今天也终于领略到什么是深搜什么是广搜的区别和特点了,其实一直不太懂什么时候用深搜,什么时候用广搜,虽然两种都有用过,但是都是结合解题报告或者其他途径来做的,总感觉深搜用起来比较顺手,感觉很多题都可以用深搜来解决,但是今天遇到的这个题用深搜怎么想方设法都不好用,结果应该正确,但是就是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; }