首页 > 技术文章 > water

qqq1112 2020-08-28 15:57 原文

题目描述:

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

一场大雨后,由于地势高低不同,许多地方都积存了不少降水。给定每个小块的高度,求每个小块的积水高度。

注意:假设矩形地外围无限大且高度为$0$。

输入格式:

第一行两个非负整数$n$,$m$。

接下来一个$n$ $*$ $m$的矩阵,表示每个小块的高度。

输出格式:

输出一个$n$ $*$ $m$的矩阵,表示每个小块的积水高度。

输入样例:

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

输出样例:

0 0 0
0 1 0
0 0 1

数据范围:

$n$,$m$ $≤$ $300$,小块高度 $≤$ $10$9




思路:

首先可以了解到积水高度和周围最高的小块的高度有关。

对于小块$i$,它的积水高度会与四周最高的山峰的最低值相等,如木桶原理。

因此可以考虑对于每个小块$i$,将它与它四周的小块连边,边权为两座山峰中的最大值,然后跑最小生成树,最后通过dfs求得周围最高山峰中的最低的那一个即为它的积水高度。

对于在边界上的小块,只需要与定义$0$号点为边界外的点连边,然后$0$号点的高度为$0$。

代码:

 1 #include <bits/stdc++.h>
 2 #define INF 0x3f3f3f3f
 3 using namespace std;
 4 int n, m, q[1010][1010], z, fa[1000010], num, head[1000010];
 5 struct Tree {int x, y, z;}tree[2000010];
 6 struct node {int next, to, val;}stu[2000010];
 7 int cmp(Tree a, Tree b) {return a.z < b.z;}
 8 int find(int x) {return fa[x] == x ? fa[x] : fa[x] = find(fa[x]);}
 9 void unity(int x, int y) {fa[find(x)] = find(y); return;}
10 void add(int x, int y, int z) {stu[++num].next = head[x], stu[num].to = y, stu[num].val = z, head[x] = num; return;}
11 void edge(int ax, int ay, int bx, int by)
12 {
13     int numa, numb;
14     if(ax < 1 || ay < 1 || ax > m || ay > n) numa = 0; else numa = (ax - 1) * m + ay;
15     if(bx < 1 || by < 1 || bx > m || by > n) numb = 0; else numb = (bx - 1) * m + by;
16     tree[++z].x = numa, tree[z].y = numb, tree[z].z = max(q[ax][ay], q[bx][by]);
17     tree[++z].x = numb, tree[z].y = numa, tree[z].z = max(q[ax][ay], q[bx][by]);
18     return;
19 }
20 void kruskal()
21 {
22     for(int i = 1; i <= n * m; ++i) fa[i] = i;
23     sort(tree + 1, tree + z + 1, cmp);
24     for(int i = 1; i <= z; ++i)
25     {
26         if(find(tree[i].x) != find(tree[i].y))
27         {
28             unity(tree[i].x, tree[i].y);
29             add(tree[i].x, tree[i].y, tree[i].z), add(tree[i].y, tree[i].x, tree[i].z);
30         }
31     }
32     return;
33 }
34 void dfs(int u, int father, int sum)
35 {
36     for(int i = head[u]; i; i = stu[i].next)
37     {
38         int k = stu[i].to;
39         if(k == father) continue;
40         int xx = k / m + 1, yy = k % m;
41         if(!yy) --xx, yy = m;
42         q[xx][yy] = max(sum, stu[i].val) - q[xx][yy];
43         dfs(k, u, max(sum, stu[i].val));
44     }
45     return;
46 }
47 int main()
48 {
49     scanf("%d %d", &n, &m);
50     for(int i = 1; i <= n; ++i) for(int j = 1; j <= m; ++j) scanf("%d", &q[i][j]);
51     for(int i = 1; i <= n; ++i) for(int j = 1; j <= m; ++j) edge(i, j, i - 1, j), edge(i, j, i + 1, j), edge(i, j, i, j - 1), edge(i, j, i, j + 1);
52     kruskal();
53     dfs(0, -1, -INF);
54     for(int i = 1; i <= n; ++i) {for(int j = 1; j <= m; ++j) printf("%d ", q[i][j]); puts("");}
55     return 0;
56 }

 

推荐阅读