回忆BFS
上次我们已经回忆了简单的dfs,相信大家对搜索已经有了一点了解,对搜索也不会那么陌生了。那么我们现在就来更加深入的了解一下搜索,学习更上一层难度的搜索方法————————————BFS!!
哇!一听BFS这个方法的名称,就让人觉得是那么的神圣!那么难!(咳咳,难其实也没那么难~~),那么,接下来就让我们进入神奇的BFS之旅吧!
抽象“概念”:BFS顾名思义,更在乎搜索的范围,每次都尽可能把能搜索到的范围都搜索到,然后逐步扩展。这样在求最短步数,或者最短的序列问题时,第一次搜到的肯定时一般的最优解。
接下来给大家一道框架题目:
有n个城市,给定城市a到城市b的路径(当然不止连同两个城市),求从城市S带城市B的最短路。
题目分析:诶诶?这不是图论中的最短路吗??怎么会是BFS??嘿嘿~当然是楼。具体看模板:
int adj[N][N],S,T,n;
int q[N]={},s[N]={},head=0,tail=0;
……(此处应为输入及初始化)
q[++tail]=S;vis[S]=true;(将初始化节点S塞入队列)
while (head<=tail){
int X=a[head++];//取对头
for (inti=1;i<=n;i++)
if (adj[x][i]&&!vis[i]){
q[++tail]=i;vis[i]=true;
if (i==T)break;处理;//ok
}
}
好吧这个模板其实是有点抽象的。。
二、接下来是求最短路径的代码(其实也就改了一点):
int adj[N][N],S,T,n;
int q[N]={},s[N]={},head=0,tail=0,dis[N]={};
……(此处应为输入及初始化)
q[++tail]=S;vis[S]=true;(将初始化节点S塞入队列)
while (head<=tail){
int X=a[head++];//取对头
for (inti=1;i<=n;i++)
if (adj[x][i]&&!vis[i]){
q[++tail]=i;vis[i]=true;//将新状态加入队尾
dis[i]=dis[x]+1;//步数+1
if (i==T)break;处理;//ok
}
}
啊哈!这就是一道不太正宗的模板!接下来一道真正的模板:
int bfs(){
初始化,初始状态存入队列;
队列首指针head=0;尾指针 tail=1;
do{
指针head后移以一位,指向带扩展节点;
for (inti=1;i<=max;i++){
if (子节点符合条件){
tali指针加一,把新节点存入队尾;
if (新节点已产生节点重复) 删去该节点(取消入队,tail减一);
else
if(新节点是目标节点) 输出并退出
}
}
}while(head<tail);//队列为空
}
三、经典例题:
一、勇士与公主
题目简述:有一个n*n的矩阵,其中矩阵中的元素分别有'.'(空地),'#'(墙),'T'(勇士的位置)和'S'(公主的位置)。其实每次都能上下左右走,问最少走几步?
题目分析:额~~这道题其实是我简化过10000倍的~~应该很简单吧~~开始时就只要把墙处理一下,在找出骑士位置然后公主位置后按题一bfs就行了。
那么具体代码如下(完整代码就只发这么一题):
#Include<bits/stdc++.h>
using namespacestd;
intxx,yy,xx1,yy1,n,q[1001][3]={},head=0,tail=0,dis[1001][1001]={};
char ch;//输入用
bool f[1001][1001]={};//判断当前路是否可走
int dx[5]={0,0,1,-1}
int dy[5]={1,-1,0,0}//方向
void bfs(){
for (inthead=1;head<=tail;head++){
for (inti=0;i<=3;i++){
inttx=q[head][1]+dx[i],ty=q[head][2]+dy[i];
if (f[tx][ty){
if (tx==xx1&&ty==yy1)cout<<dis[tx][ty];
else {
q[+tail][1]=tx;q[tail][2]=ty;
}
}
}
}
int main(){
cin>>n;
for (inti=1;i<=n;i++)
for (intj=1;j<=n;j++){
f[i][j]=1;//现将范围内的东东赋值为可走,避免走出接
if (ch=='T')xx=i,yy=j;//记录骑士位置
if (ch=='S') xx1=i,yy1=j;//记录公主位置
if (ch=='#')f[i][j]=0;//墙,不能走
}
q[+tail][1]=xx;q[tail][2]=yy;
bfs();//bfs
return ;
}
{因为代码是现成敲的,所以不保证对,但致思路是没问题的
二、思考:如果加上守卫,没杀死一个守卫需要耗费一个单位时间,那怎么办呢?
题目分析:还是一样,如果当前点有守卫,那么就记录状态,一旦遇到,就额外多加一个单位的时间,再讲状态清空,继续bfs。
这题代码就不给了,大家自己想把。