You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4.1 KiB

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

AcWing 1097. 池塘计数

一、题目描述

农夫约翰有一片 NM 的矩形土地。

最近,由于降雨的原因,部分土地被水淹没了。

现在用一个字符矩阵来表示他的土地。

每个单元格内,如果包含雨水,则用 W 表示,如果不含雨水,则用 .表示。

现在,约翰想知道他的土地中形成了多少片池塘。

每组相连的积水单元格集合可以看作是一片池塘

每个单元格视为与其 上、下、左、右、左上、右上、左下、右下 八个邻近单元格相连。

请你输出共有多少片池塘,即矩阵中共有多少片相连的 W块。

输入格式 第一行包含两个整数 NM

接下来 N 行,每行包含 M 个字符,字符为”W”或”.”,用以表示矩形土地的积水状况,字符之间没有空格。

输出格式 输出一个整数,表示池塘数目。

数据范围

1N,M1000

输入样例

10 12
W........WW.
.WWW.....WWW
....WW...WW.
.........WW.
.........W..
..W......W..
.W.W.....WW.
W.W.W.....W.
.W.W......W.
..W.......W.

输出样例

3

二、总结

Flood \ Fill问题比较经典的作法有两种: 宽搜深搜,代码写好的话,两种方法没有区别,不存在说数据量大了就深搜不了的问题。

要严格使用yxc老师讲的hh=0,tt=-1的模拟队列方式,不要使用STL中的queue!,原因很简单,有时候,比如斜率优化中,我们可能还要从队头出队列,那样的话还需要使用 双端队列 ,还如直接来这个模拟更方便!

三、广度优先搜索

#include <bits/stdc++.h>

using namespace std;

const int N = 1010, M = N * N;

typedef pair<int, int> PII;
#define x first
#define y second

// 方向数组
int dx[] = {1, 0, -1, 0, 1, -1, 1, -1};
int dy[] = {0, 1, 0, -1, 1, -1, -1, 1};

int n, m;
char g[N][N];

int ans;

PII q[M];
// 宽搜
void bfs(int sx, int sy) {
    int hh = 0, tt = -1;

    q[++tt] = {sx, sy}; // 起点入队列
    g[sx][sy] = '.';    // 标识为已使用过,防止回头路

    while (hh <= tt) {
        PII t = q[hh++]; // 一边取队列头,一边出队列
        for (int i = 0; i < 8; i++) {
            int tx = t.x + dx[i];
            int ty = t.y + dy[i];
            if (g[tx][ty] == 'W') {
                g[tx][ty] = '.';
                q[++tt] = {tx, ty};
            }
        }
    }
}
int main() {
    // n行m列 
    cin >> n >> m;
    // 读入地图
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            cin >> g[i][j];

    // 枚举每个位置
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            if (g[i][j] == 'W') {
                bfs(i, j); // 开始宽搜
                ans++;     // 找到一块
            }
    printf("%d\n", ans);
    return 0;
}

四、深度优先搜索

#include <bits/stdc++.h>

using namespace std;
const int N = 1010;
int n, m, ans;
char g[N][N];

// 方向数组
int dx[] = {1, 0, -1, 0, 1, -1, 1, -1};
int dy[] = {0, 1, 0, -1, 1, -1, -1, 1};

void dfs(int x, int y) {
    g[x][y] = '.'; // 这样可以不用使用st数组
    for (int i = 0; i < 8; i++) {
        int tx = x + dx[i], ty = y + dy[i];
        if (g[tx][ty] == 'W') dfs(tx, ty);
    }
}
int main() {
    cin >> n >> m;
    // 使有深度优先搜索时注意下标从1开始这样相当于构建了一个四周为0的墙不会越界
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            cin >> g[i][j];

    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            if (g[i][j] == 'W') { // 找到“ W ”.
                dfs(i, j);
                ans++; // 统计答案
            }
    printf("%d\n", ans);
    return 0;
}