AcWing 寒假每日一题 2021-01-12 红与黑

AcWing 1113. 红与黑(传送门)
在这里插入图片描述在这里插入图片描述
思路分析:
这个题可以用 bfs 宽度优先搜索 或者 dfs 深度优先搜索

  • bfs

    • 优点:
      • 可求最短距离(第一次搜到的点,一定是最短的)
      • 更好理解,比较符合人的思维方式
    • 缺点:
      • 需要自己手动写队列
  • dfs

    • 优点:
      • 更方便
      • 代码较短
    • 缺点:
      • 在某些OJ上存在暴栈的可能
      • 思维更像计算机思维,不好理解

那么下面就先说一下 bfs 宽搜 也就是 Flood Fill算法 中文名:洪水灌溉

时间复杂度 O(mn) ,m和n分别为矩阵的长宽

bfs 事实上是一个点一个点的前进,就先遍历当前所在点的上右下左四个方向,然后将可以走的点存入队列中,并从队列中删除当前点,然后对队列中的所有点进行相同的操作,直到队列中没有符合要求点。

AC代码:

#include <iostream>
#include <cstdio>
#include <queue>

#define x first
#define y second
#define ll long long
using namespace std;

typedef pair<int,int> PII;	// 坐标存法
const int N = 25;

char a[N][N];

// 顺序:上右下左
int dx[] = {
    
    -1,0,1,0};
int dy[] = {
    
    0,1,0,-1};
int w,h;

int bfs(int sx,int sy) {
    
    
    queue<PII> q;		// 队列中存坐标
    q.push({
    
    sx,sy});
    a[sx][sy] = '#';    // 标记一下初始位置
    int res = 0;        // 最终结果,表示能搜到点的数量,也就是最后的答案
    while(q.size()) {
    
    
        auto t = q.front();
        q.pop();
        res++;  // 每次从队列中取出一个点,结果 +1
        for(int i = 0;i < 4; i++) {
    
    
            int x = t.x + dx[i];
            int y = t.y + dy[i];
            // 遍历上右下左 4个位置,当该位置出界,或者已经被走过
            if( x < 0 || x >= h || y < 0 || y >= w || a[x][y] != '.')
                continue;
            // 如果可以扩展的话,首先先标记一下
            a[x][y] = '#';
            // 然后把当前坐标存在队列中
            q.push({
    
    x,y});
        }
    }
    return res;
}

int main() {
    
    
    int x,y;
    while(~scanf("%d%d",&w,&h)) {
    
    
        if( w == 0 && h == 0)
            break;
        for(int i = 0;i<h;i++)
            cin >> a[i];
        for(int i = 0;i<h;i++)
            for(int j = 0; j < w; j++)
                if(a[i][j] == '@') {
    
    
                    x = i;
                    y = j;
                }
        cout << bfs(x,y) << endl;
    }
    return 0;
}

再来说下 dfs 深搜

dfs 事实上描述的是一个不断递归和回溯的过程,先从一个有效的方向出发,按照上右下左顺序,一直进行下去,直到没有有效方向,然后往前回溯,直到所有已经走过的点的有效方向全部失效,最后得出答案。

AC代码:

#include <iostream>
#include <cstdio>

#define ll long long
using namespace std;

const int N = 25;

char a[N][N];

// 顺序:上右下左
int dx[] = {
    
    -1, 0, 1, 0};
int dy[] = {
    
    0, 1, 0, -1};
int w, h;

int dfs(int x, int y) {
    
    
    int res = 1;
    // 首先将起始点进行标记
    a[x][y] = '#';
    // 枚举上右下左四个临格
    for (int i = 0; i < 4; i++) {
    
    
        // 写出新格坐标
        int new_x = x + dx[i];
        int new_y = y + dy[i];
        // 如果在界内,且可以走的话,累加结果,并且递归新的dfs
        if( new_x >= 0 && new_x < h && new_y >= 0 && new_y < w && a[new_x][new_y] == '.')
            res += dfs(new_x,new_y);
    }
    return res;
}

int main() {
    
    
    int x, y;
    while (~scanf("%d%d", &w, &h)) {
    
    
        if (w == 0 && h == 0)
            break;
        for (int i = 0; i < h; i++)
            cin >> a[i];
        for (int i = 0; i < h; i++)
            for (int j = 0; j < w; j++)
                if (a[i][j] == '@') {
    
    
                    x = i;
                    y = j;
                }
        cout << dfs(x, y) << endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_45654671/article/details/112622314