寻宝图(图论)

216 阅读1分钟

L2-048 寻宝图 (pintia.cn)

题目分析

给定一幅地图,其中有水域,有陆地。被水域完全环绕的陆地是岛屿。有些岛屿上埋藏有宝藏,这些有宝藏的点也被标记出来了。本题就请你统计一下,给定的地图上一共有多少岛屿,其中有多少是有宝藏的岛屿。

输入格式:

输入第一行给出 2 个正整数 N 和 M(1<N×M≤105),是地图的尺寸,表示地图由 N 行 M 列格子构成。随后 N 行,每行给出 M 位个位数,其中 0 表示水域,1 表示陆地,2-9 表示宝藏。
注意:两个格子共享一条边时,才是“相邻”的。宝藏都埋在陆地上。默认地图外围全是水域。

输出格式:

在一行中输出 2 个整数,分别是岛屿的总数量和有宝藏的岛屿的数量。

输入样例:

10 11
01000000151
11000000111
00110000811
00110100010
00000000000
00000111000
00114111000
00110010000
00019000010
00120000001

输出样例:

7 2

题目分析

这是一道 dfsdfs 求连通块的题目,并需要记录特殊连通块(岛屿中埋有宝藏)的数量。

相对于以往做这类题目的解法来看,本题主要有一点不同,即 nm1e5n\cdot m\le 1e5,意为 n,mn,m 最大值均可以取到 1e51e5

以往题目中,我是直接开一个全局数组 g[N][N] 存取图中元素,而本题若定义 N=1e5N=1e5,则会超出内存限制。

这里介绍一个新的方式,即 vector<vector<int>> g 存储不定长数组。

首先开一个全局二维 vector,再在局内开一个临时二维 vector,局内初始化方法为 vector<vector<int>> a(n + 1, vector<int> (m + 1)),将其复制到全局 vector 中。

其他会超出限制的数组均可以这样解决。

然后就是常规的求连通块问题。

Accept代码

#include <bits/stdc++.h>

using namespace std;

int n, m;
vector<vector<int>> g;
vector<vector<bool>> st;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int cnt, val;
int hav_val;

void dfs(int x, int y)
{
    st[x][y] = true;
    if (g[x][y] > 1 && !hav_val) val ++, hav_val = 1;
    for (int i = 0; i < 4; i ++)
    {
        int a = x + dx[i], b = y + dy[i];
        if (a && a <= n && b && b <= m && !st[a][b] && g[a][b])
            dfs(a, b);
    }
}

int main()
{
    cin >> n >> m;
    vector<vector<int>> a(n + 1, vector<int> (m + 1));
    vector<vector<bool>> b(n + 1, vector<bool> (m + 1));
    for (int i = 1; i <= n; i ++)
        for (int j = 1; j <= m; j ++)
        {
            char c; cin >> c;
            a[i][j] = c - '0';
        }
    g = a; st = b;
    for (int i = 1; i <= n; i ++)
        for (int j = 1; j <= m; j ++)
            if (g[i][j] && !st[i][j]) 
                hav_val = 0, cnt ++, dfs(i, j);
    cout << cnt << ' ' << val;
    return 0;
}

update:不用嵌套也能过

// dfs

#include <bits/stdc++.h>

using namespace std;

const int N = 100010;

int n, m;
vector<int> g[N], st[N];
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int cnt, val;
int u;

void dfs(int x, int y)
{
    st[x][y] = true;
    if (g[x][y] > 1 && !u) val ++, u = 1;
    for (int i = 0; i < 4; i ++)
    {
        int a = x + dx[i], b = y + dy[i];
        if (a && a <= n && b && b <= m && !st[a][b] && g[a][b])
            dfs(a, b);
    }
}

int main()
{
    cin >> n >> m;
    for (int i = 1; i <= n; i ++)
    {
        g[i].push_back(0);
        st[i].push_back(0);
        for (int j = 1; j <= m; j ++)
        {
            char c;
            scanf(" %c", &c);
            g[i].push_back(c - '0');
            st[i].push_back(0);
        }
    }
    for (int i = 1; i <= n; i ++)
        for (int j = 1; j <= m; j ++)
            if (g[i][j] && !st[i][j]) 
                u = 0, dfs(i, j), cnt ++;
    cout << cnt << ' ' << val;
    return 0;
}
// bfs
void bfs(int i, int j)
{
    queue<pair<int, int>> q;
    q.push({i, j}); st[i][j] = true;
    while (!q.empty())
    {
        auto [x, y] = q.front();
        q.pop();
        if (!u && g[x][y] > 1) val ++, u = true;
        for (int k = 0; k < 4; k ++)
        {
            int a = x + dx[k], b = y + dy[k];
            if (a && a <= n && b && b <= m && !st[a][b] && g[a][b])
            {
                q.push({a, b});
                st[a][b] = true;
            }
        }
    }
}
// function 函数

function<void(int, int)> dfs = [&](int x, int y) {};
// map存图方式
map<pair<int, int>, int> p;