Flood Fill

介绍:

可以形象的理解为洪水覆盖算法,每当我们dfs一个点,这个点就像洪水一样,把所有与它相邻的并且可以被合法的点覆盖掉。

应用场景:

通常作为解题中的一步,常用来处理有关连通块的问题

例如:求联通块个数,求每个连通块的边长。


例题1:1097. 池塘计数 - AcWing题库

#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>

#define x first
#define y second

using namespace std;

typedef pair<int, int> PII;

const int N = 1010;

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

void bfs(int x, int y)//Flood Fill
{
    queue<PII> q;
    q.push({x, y});
    st[x][y] = true;
    while(q.size())
    {
        auto t = q.front();
        q.pop();
        int sx = t.x, sy = t.y;
        for(int i = sx - 1; i <= sx + 1; i ++ )
        {
            for(int j = sy - 1; j <= sy + 1; j ++ )
            {
                if(i == sx && j == sy)  continue;
                if(i < 0 || i >= n || j < 0 || j >= m || st[i][j] || g[i][j] != 'W')    continue;
                q.push({i, j});
                st[i][j] = true;
            }
        }
    }

}

int main()
{
    cin >> n >> m;
    for(int i = 0; i < n; i ++ )    cin >> g[i];

    int cnt = 0;
    for(int i = 0; i < n; i ++ )
        for(int j = 0; j < m; j ++ )
            if(!st[i][j] && g[i][j] == 'W')
            {
                bfs(i, j);
                // cout << i << " " << j << endl;
                cnt ++ ;
            }
            
    cout << cnt << endl;
    
    return 0;
}


例题二:1098. 城堡问题 - AcWing题库

#include <iostream>
#include <cstring>
#include <queue>
#include <algorithm>

#define x first
#define y second

using namespace std;

typedef pair<int, int> PII;

const int N = 1010;

int n, m, cnt, maxn;
int g[N][N];
bool st[N][N];
int dx[4] = {0, -1, 0, 1}, dy[4] = {-1, 0, 1, 0};

void bfs(int x, int y)//Flood Fill
{
    int ans = 1;
    queue<PII> q;
    q.push({x, y});
    st[x][y] = true;
    
    while(q.size())
    {
        auto t = q.front();
        q.pop();
        int sx = t.x, sy = t.y;
        int d = g[sx][sy];
        for(int i = 0; i < 4; i ++ )
        {
            if(d >> i & 1)  continue;//有墙
            int a = sx + dx[i], b = sy + dy[i];
            if(a < 0 || b < 0 || a >= n || b >= m)  continue;//越界
            if(st[a][b])    continue;//去重
            
            q.push({a, b});
            st[a][b] = true;
            ans ++ ;
        }
    }
    maxn = max(maxn, ans);
}

int main()
{
    cin >> n >> m;
    for(int i = 0; i < n; i ++ )
        for(int j = 0; j < m; j ++ )
            cin >> g[i][j];
    
    for(int i = 0; i < n; i ++ )
        for(int j = 0; j < m; j ++ )
            if(!st[i][j])
            {
                bfs(i, j);
                cnt ++ ;
            }
    
    cout << cnt << endl;
    cout << maxn << endl;
    
    return 0;
}


例题三:1106. 山峰和山谷 - AcWing题库

#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>

#define y second
#define x first

using namespace std;

typedef pair<int, int> PII;

const int N = 1010;

int n, g[N][N];
int peak, valley;
bool st[N][N];

void dfs(int x, int y)
{
    queue<PII> q;
    q.push({x, y});
    st[x][y] = true;
    bool is_higher = false, is_lower = false;
    
    while(q.size())
    {
        auto t = q.front(); q.pop();
        int sx = t.x, sy = t.y;
        for(int i = sx - 1; i <= sx + 1; i ++ )
        {
            for(int j = sy - 1; j <= sy + 1; j ++ )
            {
                if(i == sx && j == sy)  continue;//挖去自己
                if(i < 0 || i >= n || j < 0 || j >= n) continue;//越界
                
                if(g[i][j] > g[sx][sy]) is_higher = true;
                else if(g[i][j] < g[sx][sy])    is_lower = true;
                else if(!st[i][j])
                {
                    q.push({i, j});
                    st[i][j] = true;
                }
            }
        }
    }
    
    // cout << is_higher << " " << is_lower << endl;
    
    if(is_higher && is_lower) return ;
    
    if(!is_higher)   peak ++ ;
    if(!is_lower)   valley ++ ;
    return ;
}

int main()
{
    cin >> n;
    for(int i = 0; i < n; i ++ )
        for(int j = 0; j < n; j ++ )
            cin >> g[i][j];
    
    for(int i = 0; i < n; i ++ )
        for(int j = 0; j < n; j ++ )
            if(!st[i][j])
                dfs(i, j);
    
    cout << peak << ' ' << valley << endl;
    
    return 0;
}


求每个连通块的边长

暂且认为一个点是连通块的边长当且仅当它至少有一个方向不与连通块相连

(没有遇到过类似的题,不知道对错!)

#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>

#define y second
#define x first

using namespace std;

typedef pair<int, int> PII;

const int N = 1010;

int n, g[N][N];
int peak, valley;
bool st[N][N];
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};

void dfs(int x, int y)
{
    int len = 0;
    
    queue<PII> q;
    q.push({x, y});
    st[x][y] = true;
    
    while(q.size())
    {
        auto t = q.front(); q.pop();
        int sx = t.x, sy = t.y;
        int cnt = 0;//记录有几个方向连通
        for(int i = 0; i < 4; i ++ )
        {
            int a = sx + dx[i], b = sy + dy[i];
            if(a < 0 || a >= n || b < 0 || b >= n)  continue;
            if(g[a][b] != g[sx][sy])  continue;
            if(st[a][b])    
            {
                cnt ++ ;
                continue;
            }
            q.push({a, b});
            // cout << "a:b = " << a << " " << b << endl; 
            st[a][b] = true;
            cnt ++ ;
        }
        if(cnt != 4)    len ++ ;
    }
    
    cout << "边长信息:" << len << endl;
}

int main()
{
    cin >> n;
    for(int i = 0; i < n; i ++ )
        for(int j = 0; j < n; j ++ )
            cin >> g[i][j];
    
    for(int i = 0; i < n; i ++ )
        for(int j = 0; j < n; j ++ )
            if(!st[i][j])
                dfs(i, j);
    
    
    
    return 0;
}

/*16 8
8 8 8 8 8
8 7 7 7 8
8 7 7 7 8
8 7 7 7 8
8 8 8 8 8
*/

/*16
5
8 8 8 8 8
8 8 8 8 8 
8 8 8 8 8
8 8 8 8 8 
8 8 8 8 8 
*/

/*1 1 1 1 1 1 3 4 12
5
8 7 7 7 1
8 8 8 7 2
8 6 6 6 3
8 8 9 8 4
8 8 8 8 5
*/

posted @ 2022-05-05 08:41  光風霽月  阅读(33)  评论(0编辑  收藏  举报