flood fill里的bfs、dfs

flood fill里的bfs、dfs

先来看题吧,是AcWing上的1113.红与黑。

这是一道flood fill类题,这是啥类题,我也不太懂,就先记住就好了。中文称为洪水灌溉,主要是一些与网格图相关的题目。
题目描述:
在这里插入图片描述
分析题目可得:
就是想找人能走过的黑色格子总数,将人比喻成洪水,即为洪水最终能占据的范围。

题解:
1.使用breadth-first-search,大概全称是这个吧,(以下简称bfs),中文翻译下来就是广度(宽度)优先搜索。这个可以想象一下就是和水波纹一样,一圈一圈地进行搜索,符合条件地一个一个入队,假设出队一个a,判断a的四个方向符合条件(是黑色瓷砖)地再入队,直到队列为空。出队一个结果+1,只要把队列里的东西都出队完就得到答案啦。
在这里插入图片描述

2.使用deep-first-search(以下简称dfs),中文又叫深度优先搜索,之前有人戏称它为不撞南墙不回头,我觉得挺形象的。只要找到一条可走的路(黑色方块)就会一直走下去,直到没路了就往回走,往回走的时候遇到一条之前没走过的路就会毫不犹豫地走下去,然后再撞墙,再回头,直到顺着第一条回路走回原点了为止。
在这里插入图片描述

两个方法的优缺点:
bfs:优点是这个方法还能应用在求起点到其余各点的最短距离问题,缺点是需要自己实现队列。
dfs:优点是代码简洁,写起来容易点,缺点是由于涉及了递归,有暴栈的可能(暴不暴取决于服务器的默认栈空间了)。

前面只说了使用到的搜索方法,但是还有几个问题没有解决:

1.如何让小人不走那些走过的小黑瓷砖呢?
解决方案:其实很简单,走过一次把它染成黑色就好啦。
2.当一个黑块与多个黑块相连时,在dfs中哪个优先走?
解决方案:这里定义了长度为4的dx数组和dy数组,来记录向各个方向走时的坐标变化,0、1、2、3分别对应上右下左。

好嘞,现在来看看具体代码:

头文件

#include<iostream>
#include<queue>//包含对队列处理的一系列函数

bfs

#define x first //编译器运行前会将所有的x替换成first
#define y second //同上

using namespace std;

//std::pair<int,int>将两个int数据(类型可以不同)组合成一个数据,调用时第一个为first,第二个为second 
typedef pair<int,int> PII;
const int N=25;

char g[N][N];
int n,m;//n行m列

int bfs(int sx,int sy){
    queue<PII> q;
    q.push({sx,sy});
    g[sx][sy]='#';
    int res=0;

    int dx[]={-1,0,1,0},dy[]={0,1,0,-1};
    while(q.size()){
        auto t=q.front();//auto 自定判断数据类型
        q.pop();//出队列
        ++res;
        for(int i=0;i<4;++i){
            int x=t.x+dx[i];
            int y=t.y+dy[i];
            if(x<0 || x>=n || y<0 || y>=m || g[x][y] != '.') continue;
            g[x][y]='#';
            q.push({x,y});//符合条件进入队列
        }
    }
    return res;
}

dfs

using namespace std;
const int N=25;

char g[N][N];
int n,m;//n行m列

int dfs(int x,int y){
    int dx[]={-1,0,1,0},dy[]={0,1,0,-1};
    int res=1;
    g[x][y]='#';
    int a,b;
    for(int i=0; i<4; ++i){
        a=x+dx[i],b=y+dy[i];
        if(a>=0 && a<n && b>=0 && b<m &&g[a][b]=='.')
            res+=dfs(a,b);              //递归
    }
    return res;
}

main函数
两个都是一样的,主要是进行初始化g数组以及查找了初始位置的操作。

int main(){
    int x=-1,y=-1;//初始化x,y
    while(cin>>m>>n,n||m){
        for(int i=0;i<n;++i) cin>>g[i];
        for(int i=0;i<n;++i){
            for(int j=0;j<m;++j)
                if(g[i][j]=='@'){//找到初始坐标了
                   x=i;
                   y=j;
                   break;
                }
           if(x!=-1&&y!=-1)//判断是否已经找到初始坐标了
           		break;//退出循环
         }
        cout<<bfs(x,y)<<endl;//如果用的dfs就改成dfs(x,y)就好了
    }
    return 0;
}

好啦,也不知道大家看不看得懂,有什么疑惑的话欢迎评论区一起讨论,俺也是一个刚学算法的萌新,写详细点是希望能对自己、对大家都有点帮助吧。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值