广度优先搜索

今天我们来了解一下数据结构队列的附属算法——广搜(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;
} 

大概参考一下就好了!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值