[一本通1687]积水问题题解

1687:积水问题

时间限制: 1000 ms         内存限制: 262144 KB

【题目描述】

有一块矩形土地被划分成n×m个正方形小块。这些小块高低不平,每一小块都有自己的高度。水流可以由任意一块地流向周围四个方向的四块地中,但是不能直接流入对角相连的小块中。

一场大雨后,由于地势高低不同,许多地方都积存了不少降水(这些雨水会不断下,直到积水不再上升)。

给定每个小块的高度,求每个小块的积水高度。

注意:假设矩形地外围无限大且高度为0,即从内部流出来的雨水会在外围消失。

【输入】

第一行包含两个非负整数n,m

接下来n行每行m个整数表示第i行第j列的小块的高度。

【输出】

输出n行,每行m个由空格隔开的非负整数,表示每个小块的积水高度。

【输入样例】

3 3
4 4 0
2 1 3
3 3 -1

【输出样例】

0 0 0
0 1 0
0 0 1

【提示】

【数据规模与约定】

对于20%的数据,n,m4

对于40%的数据,n,m15

对于60%的数据,n,m50

对于100%的数据,n,m300,|小块高度|109

在每一部分数据中,均有一半数据保证小块高度非负。

代码

#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;

const int N = 386;

int G[N][N];

const int dx[] = {1, -1, 0, 0};
const int dy[] = {0, 0, 1, -1};

int f[N * N];

int n, m;

int get(int u)
{
    if (f[u] == u)
        return u;
    else
        return f[u] = get(f[u]);
}

void merge(int a, int b)
{
    int fa = get(a);
    int fb = get(b);
    if (fa != fb)
        f[fa] = fb;
}

struct node
{
    int x, y;
    inline bool operator<(const node &a) const
    {
        return G[x][y] < G[a.x][a.y];
    }
} map_list[N * N];

int pos[N][N];

bool vis[N][N];

bool tag[N * N]; //流到边界

void bfs(int sx, int sy)
{
    queue<node> Q;
    Q.push(node({sx, sy}));
    vis[sx][sy] = true;
    int sp = pos[sx][sy];
    vector<node> L;
    while (!Q.empty())
    {
        L.push_back(Q.front());
        int ux = Q.front().x;
        int uy = Q.front().y;
        Q.pop();
        for (int i = 0; i < 4; i++)
        {
            int vx = ux + dx[i];
            int vy = uy + dy[i];
            if (vx > 0 && vx <= n && vy > 0 && vy <= m)
            {
                if (G[vx][vy] < G[ux][uy] && tag[get(pos[vx][vy])])
                    tag[get(sp)] = true;
                if (vis[vx][vy] || G[vx][vy] != G[ux][uy])
                    continue;
                Q.push(node({vx, vy}));
                vis[vx][vy] = true;
                merge(pos[vx][vy], sp);
            }
        }
    }
    for (auto i : L)
    {
        int ux = i.x;
        int uy = i.y;
        for (int j = 0; j < 4; j++)
        {
            int vx = ux + dx[j];
            int vy = uy + dy[j];
            if (vx > 0 && vx <= n && vy > 0 && vy <= m && vis[vx][vy])
            {
                if (G[ux][uy] > G[vx][vy] && !tag[get(pos[vx][vy])])
                    merge(pos[vx][vy], sp);
            }
        }
    }
}

int idx[N * N][2];

int main()
{
    cin >> n >> m;
    n += 2;
    m += 2;
    int tot = 0;
    for (int i = 2; i < n; i++)
        for (int j = 2; j < m; j++)
        {
            cin >> G[i][j];
        }
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
        {
            map_list[++tot] = {i, j};
            f[tot] = tot;
            idx[tot][0] = i;
            idx[tot][1] = j;
            pos[i][j] = tot;
            if (i == 1 || i == n || j == 1 || j == m)
                tag[tot] = true;
        }
    sort(map_list + 1, map_list + tot + 1);
    for (int i = 1; i <= tot; i++)
    {
        if (!vis[map_list[i].x][map_list[i].y])
            bfs(map_list[i].x, map_list[i].y);
    }
    for (int i = 2; i < n; i++)
    {
        for (int j = 2; j < m; j++)
        {
            int p = get(pos[i][j]);
            cout << G[idx[p][0]][idx[p][1]] - G[i][j] << ' ';
        }
        cout << endl;
    }
    return 0;
}
上一篇:杭电oj HDOJ 2076 夹角有多大(题目已修改,注意读题)


下一篇:安卓逆向——Dalvik虚拟机操作码