广度优先搜索2018-08-14

这道题:https://vjudge.net/contest/246999#problem/D
这个显然就是一个BFS问题的模板,首先将输入的数都翻转(0->1 1->0)这样就可以潜移默化地将边界都设为0,输出就需要逆序输出,所以输出时我用的是递归方法而已,BFS是这样实现的:首先,一旦找到了一个是”1”,那就将它设为0,表示已经走过了,然后,再判断它的上下左右,一旦是”1”就将它也设为0,因为题目保证只有一个路径走法,所以我们只需要再存下走的坐标即可,同时,在运用方向数组。

#include <iostream>//注意,在POJ上,不能用万能头文件!!!(我表示被坑了好久)
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn=1000+10;
int a[6][6],q[maxn*maxn][3],d[5][2]={{0,1},{1,0},{-1,0},{0,-1}};//初始化,d数组表示4个方向的不同坐标
void dg(int x){//递归输出函数
    if(x==0)//如果是0,就自然退出输出
       return ;
    dg(q[x][2]);//继续输出下一个坐标
    printf("(%d, %d)\n",q[x][0]-1,q[x][1]-1);//打印
}
int main(){
    int s=0,t=1,k;
    for(int i=1;i<=5;i++)//输入5*5数组
        for(int j=1;j<=5;j++){
            cin>>k;
            a[i][j]=1-k;//这里很关键!将1变成0,0变成1,潜移默化地将四周建立了边界(超过5*5的都为0)
        }
    q[1][1]=q[1][0]=1;//先将前面两个设为1
    a[1][1]=0;//从(1,1)开始走,先将(1,1)设为0,表示已走
    while(s<t){//正式开始BFS,当头<尾
        s++;//向后移一位
        if(q[s][0]==5&&q[s][1]==5){//如果到达了终点(5,5),就直接跳出
            k=s;
            break;
        }
        for(int i=0;i<4;i++){//这里是判断四个方位,即上下左右
            int xx=q[s][1]+d[i][1];//x坐标
            int yy=q[s][0]+d[i][0];//y坐标
            if(a[xx][yy]){//如果这个数(xx,yy)可以走
                q[++t][0]=xx;//横坐标更新
                q[t][1]=yy;//纵坐标更新(注意,这里t不能加1)
                a[xx][yy]=0;//标位已走
                q[t][2]=s;//存下正确步骤
            }
        }
    }
    dg(k);//直接调用k,从k开始输出
    return 0;//一个好的程序猿评判标准
}

传送门:https://vjudge.net/contest/246999#problem/E
这一道题可以用DFS也可以用BFS,不过今天学的是BFS那就用BFS吧,跟上一题类似,这一道题只不过是在上一道模板题再增加了计数器的使用,只要定义一个ans存答案就可以了,我甚至觉得这一题还是比上一题简单·······这一题就是每找到一个水域就向上下左右扩展,并如果可以继续扩张(上下左右左上左下右上右下为1),就继续设为已灌水(QAQ),那么,这道题分析到这里了,上代码:

#include <iostream>//坑人的POJ,不能用万能头文件
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn=100+5,maxm=10000+10;
int n,m,s,t,ans,a[maxn][maxn],q[maxm][2],d[9][2]={{1,1},{1,0},{1,-1},{0,-1},{0,1},{-1,0},{-1,1},{-1,-1}};//初始化定义坐标数组
char c;//一个字母
int main(){ 
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){//输入,如果是"W"就代表有水,设为1,否则就设为0。和上一题一样,这种操作同样潜移默化地将四周设置了一层无形的屏障,如果超过n行m列,就都是0,走无可走。
            cin>>c;
            a[i][j]=c=='W'?1:0;//三目,也可以如下写:
            /*
            if(c=='W')
               a[i][j]=1;
            else
               a[i][j]=0;
            */
        }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(a[i][j]){//如果a[i][j]还没有被灌水,那就灌水吧!!!
                ans++;//计数器(存储找到的湖泊总数)
                a[i][j]=0;//设为已经走过
                q[1][1]=j;//坐标初始化
                q[1][0]=i;
                s=0;//队列首尾初始化
                t=1;
                while(s<t){//如果首<尾,BFS
                    s++;//首加一
                    for(int k=0;k<8;k++){//向四周的8个方向扩展灌水
                        int xx=q[s][0]+d[k][0];//存储当前的x坐标和y坐标
                        int yy=q[s][1]+d[k][1];
                        if(a[xx][yy]){//如果没有灌过,就继续灌
                            q[++t][0]=xx;//同样存下新一轮坐标
                            q[t][1]=yy;
                            a[xx][yy]=0;//设为已经灌过水了
                            //和上一题不同的是,这里不需要输出步骤,只需要算出湖泊总数即可,那么也就不需要多定义一个小的单元数组
                        }
                    }
                }
            }
    cout<<ans;//输出
    return 0;//一个好的程序猿评判标准
}

第三题:https://www.luogu.org/problemnew/show/P1588
这一题我运用到的是一些队列的知识,什么?你没有学过队列?那么,你应该安利一下我们教练的blog:cnyali->真正的大佬:传送门https://blog.csdn.net/cnyali/article/details/78091763
由于老师给的题目没有要输入n组这个条件,所以这里也不用加n组数据了。
这里用到了队列的知识,首先,需要特判一下,如果奶牛在农夫的前面,可怜的农夫就只能直接一步一步退后那就只要输出奶牛和农夫的距离之差即可。程序一开始将n入队,然后分别考虑农夫的三种走法:+1,-1,*2,当队列不空,就广搜三种走法,先将队列的第一个数提取出来存在x中(具体操作:q.front()),再将它原先位置提出队列(q.pop),如果x就直接等于m,也就是农夫抓到了逃跑的奶牛(fkq),直接输出即可,否则,如果三种状态没有超过最大限制,继续BFS三种情况(+1,-1,*2)
代码如下:

#include <bits/stdc++.h>//终于摆脱了万恶的POJ,可以用万能头文件了!!!23333
using namespace std;
const int maxn=200000+10;
int f[maxn],n,m;
queue<int>q;//定义一个名字为q的整形队列
int main(){
    int n,m;
    cin>>n>>m;
    if(m<=n){//特判,如果农夫在奶牛前面,那么,农夫只能一步步倒退
        cout<<n-m;
        return 0;
    }
    for(int i=1;i<=maxn;i++)//首先,将所有可能的走到的地方都设为-1,表示都没有走过
        f[i]=-1;
    f[n]=0;//那么,第n个就该设为0
    q.push(n);//先将n入队
    while(!q.empty()){//当队列q不空
        int x=q.front();//将q的第一个数提取出来,存在x里面
        q.pop();//将原来的第一个数的位置提出
        if(x==m){//如果已经抓到了奶牛(fkq),直接输出
            cout<<f[x];
            return 0;
        }
        if(x*2<=maxn&&f[x*2]==-1){//如果可以往*2的方向走,那么需要判断那里有没有被走过,因为如果没有这个条件,那么农夫可能一直来回跳动,一直跳到世界毁灭·····还有要判断会不会超界
            q.push(x*2);//将x*2入队
            f[x*2]=f[x]+1;//标记
        }
        if(x+1<=maxn&&f[x+1]==-1){//如上
            q.push(x+1);
            f[x+1]=f[x]+1;
        }
        if(x>1&&f[x-1]==-1){//这里第一个条件有所不同,如果x-1>0,就是x-1可以走,其他的还是一样
            q.push(x-1);
            f[x-1]=f[x]+1;
        }
    }
    return 0;//一个好的程序猿评判标准
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
广度优先搜索是一种用于遍历或搜索图的算法,它从起始节点开始,逐层向外遍历,直到找到目标节点或遍历完整张图。具体实现过程中,可以使用队列来存储待遍历的节点,先将起始节点加入队列,然后依次取出队列中的节点,将其未访问过的邻居节点加入队列,直到队列为空或者找到目标节点为止。\n\广度优先搜索的时间复杂度为O(V+E),其中V为节点数,E为边数。在实际应用中,广度优先搜索常用于寻找最短路径、连通性检测等问题。\n\下面是一个简单的Pyth代码示例,演示了如何使用广度优先搜索遍历图:\n\```pyth\from collections impor dequ\n\# 定义图的邻接表表示\graph = {\ 'A' ['B', 'C'],\ 'B' ['A', 'D', 'E'],\ 'C' ['A', 'F'],\ 'D' ['B'],\ 'E' ['B', 'F'],\ 'F' ['C', 'E']\}\n\# 广度优先搜索函数\f bfs(graph, star, ):\ queu = dequ() # 定义队列\ queu.app(star) # 将起始节点加入队列\ visi = s() # 定义已访问集合\ visi.(star) # 将起始节点标记为已访问\n\ whi queu\ = queu.pplef() # 取出队列中的节点\ if == # 如果找到目标节点,返回Tru\ retur Tru\ for neighbor i graph[] # 遍历当前节点的邻居节点\ if neighbor i visi # 如果邻居节点未被访问过,加入队列并标记为已访问\ queu.app(ighbor)\ visi.(ighbor)\n\ retur Fals # 如果队列为空仍未找到目标节点,返回Fals\n\# 示例:在图中查找从节点A到节点F的路径是否存在\pri(bfs(graph, 'A', 'F'))\n\```\n\

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值