今天我们来了解一下数据结构队列的附属算法——广搜(BFS)
首先,通过一道简单的水题来了解广搜:
找从城市A到城市H的最短路线,并输出。
这其实不需要懂什么脑子,就是让你熟悉BFS的模板,所以看代码:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int a[9][9]={{0,0,0,0,0,0,0,0,0},
{0,1,0,0,0,1,0,1,1},
{0,0,1,1,1,1,0,1,1},
{0,0,1,1,0,0,1,1,1},
{0,0,1,0,1,1,1,0,1},
{0,1,1,0,1,1,1,0,0},
{0,0,0,1,1,1,1,1,0},
{0,1,1,1,0,0,1,1,0},
{0,1,1,1,1,0,0,0,1}};//用邻接矩阵储存,1表示通,0表示不通
int l[1001],c[1001],ans,ki[1001];
int last[1001],p[1001];
void out(int d){
int len=1;
while(d){
last[len]=l[d];len++;
d=p[d];
}
len--;
for(int i=len;i>1;i--){
printf("%c->",last[i]+'A'-1);
}
printf("%c\n",last[1]+'A'-1);
exit(0);
}
int bfs(){
int head=0,tail=1;
l[tail]=1;
c[1]=1;
p[tail]=0;
do{
head++;
for(int i=1;i<=8;i++)
if(a[l[head]][i] || c[i]);
else{
c[i]=1;
l[++tail]=i;
p[tail]=head;
if(i==8)out(tail);//**
}
}while(head<tail);
}
int main(){
int i,j,k,n,m;
bfs();
printf("%d\n",ans);
return 0;
}
我们重点看一下标注了**的地方:搜索树
广搜是一层一层地寻找,所以当我们找到的第一个成功节点,就是最短路径,大家最好记下来这棵树,以后的搜索中会经常用到。
好了,第一题大家想必已经吃透,那么我们来看看第二题:
细胞计数,求在一个n*m的矩阵中的细胞个数。
1≤m≤50;
1≤n≤80
注意:如果一个小细胞的旁边还有另一个小细胞,那么将他们视为同一个细胞!
这里主要注意思想:如果深搜,(m,n)=(50,80)的数据一定过不了。所以广搜就要派上用场了!每找到一个细胞,那么就把细胞总个数加1,同时寻找与它相邻的细胞,标记。最后输出总细胞数。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int a[1001][1001]={0},que[1001],que1[1001],fi,n,m;
int w[5]={0,1,0,-1,0},w1[5]={0,0,1,0,-1},fj,ans,ans1;
int bfs(int f,int l){
int head=0,tail=1;
que[1]=f,que1[1]=l;a[f][l]=0;
do{
head++;
for(int i=1;i<=4;i++){
int x=w[i]+que[head];
int y=w1[i]+que1[head];
if(x>0 && y>0 && x<=n && y<=m && a[x][y]){
a[x][y]=0;tail++;
que[tail]=x;
que1[tail]=y;
}
}
}while(head<tail);
}
int main(){
int i,j,k;
scanf("%d%d\n",&n,&m);
for(i=1;i<=n;i++)
for(j=1;j<=m+1;j++){
char c;
scanf("%c",&c);
a[i][j]=c-'0';
if(a[i][j]!=0){
if(a[i-1][j] || a[i][j-1])continue;
else ans++;
}
}
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
if(a[i][j]){
bfs(i,j);
ans1++;
}
printf("%d %d\n",ans,ans1);
return 0;
}
/* 样例
4 10
0234500067
1034560500
2045600671
0000000089
*/
这里需要说明的是,如果n,m再大一些,你需要使用计算ans的方法,而不是计算ans1的方法。
第三题与第一题大致相仿,是NOIP1995 T4,有兴趣的可以去做。
第四题,迷宫问题,就是给定起点和终点的坐标,使用广搜模板的一道水题,给大家一些样例吧!1表示不可以走,0表示可以走。
输入样例1: 输入样例2:
8 5 8 5
1 1 1 1 1 1 1 1 1 1
0 0 0 0 1 0 0 0 0 1
1 1 1 0 1 1 1 1 0 1
1 0 0 0 1 1 0 0 0 1
1 0 0 1 1 1 0 0 1 1
1 0 0 0 1 1 0 0 0 1
1 1 1 0 1 1 1 1 1 1
1 0 0 0 1 1 0 0 0 1
2 1 8 4 2 1 8 4
输出样例1: 输出样例2:
2,1 no way.
2,2
2,3
2,4
3,4
4,4
4,3
5,3
6,3
6,4
7,4
8,4
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int a[100001],b[100001],lj,fj;
int jz[1001][1001],n,m,li,fi;
int w[5]={0,1,0,-1};
int w1[5]={1,0,-1,0};
int p[100001];
int last[100001];
void out(int d){
int len=0;
while(d){
last[++len]=d;
d=p[d];
}
for(int i=len;i>=1;i--)
printf("%d,%d\n",a[last[i]],b[last[i]]);
exit(0);
}
void bfs(){
int head=0,tail=1;
a[tail]=fi;b[tail]=fj;
jz[fi][fj]=-1;p[tail]=0;
do{
head++;
for(int i=0;i<4;i++){
int x=w[i]+a[head];
int y=w1[i]+b[head];
tail++;
a[tail]=x;
b[tail]=y;
p[tail]=head;
if(x>n || y>m || x<1 || y<1 || jz[x][y]==-1)tail--;
else{
jz[x][y]=-1;
if(x==li && y==lj)out(tail);
}
}
}while(head<tail);
}
int main(){
freopen("1.out","w",stdout);
int i,j,k;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
for(j=1;j<=m;j++){
scanf("%d",&jz[i][j]);
if(jz[i][j]!=0)jz[i][j]=-1;
}
scanf("%d%d%d%d",&fi,&fj,&li,&lj);
if(!jz[fi][fj] && !jz[li][lj])bfs();
else printf("no way.\n");
printf("no way.\n");
return 0;
}
大概参考一下就好了!!