Description
AKD市处在一个四面环山的谷地里。最近一场大暴雨引发了洪水,AKD市全被水淹没了。Blue Mary,AKD市的市
长,召集了他的所有顾问(包括你)参加一个紧急会议。经过细致的商议之后,会议决定,调集若干巨型抽水机,
将它们放在某些被水淹的区域,而后抽干洪水。你手头有一张AKD市的地图。这张地图是边长为m*n的矩形,被划分
为m*n个1*1的小正方形。对于每个小正方形,地图上已经标注了它的海拔高度以及它是否是AKD市的一个组成部分
。地图上的所有部分都被水淹没了。并且,由于这张地图描绘的地面周围都被高山所环绕,洪水不可能自动向外排
出。显然,我们没有必要抽干那些非AKD市的区域。每个巨型抽水机可以被放在任何一个1*1正方形上。这些巨型抽
水机将持续地抽水直到这个正方形区域里的水被彻底抽干为止。当然,由连通器原理,所有能向这个格子溢水的格
子要么被抽干,要么水位被降低。每个格子能够向相邻的格子溢水,“相邻的”是指(在同一高度水平面上的射影
)有公共边。
Input
第一行是两个数m,n(1<=m,n<=1000). 以下m行,每行n个数,其绝对值表示相应格子的海拔高度;若该数为正
,表示他是AKD市的一个区域;否则就不是。请大家注意:所有格子的海拔高度其绝对值不超过1000,且可以为零.
Output
只有一行,包含一个整数,表示至少需要放置的巨型抽水机数目。
Sample Input
6 9
-2 -2 -1 -1 -2 -2 -2 -12 -3
-2 1 -1 2 -8 -12 2 -12 -12
-5 3 1 1 -12 4 -6 2 -2
-5 -2 -2 2 -12 -3 4 -3 -1
-5 -6 -2 2 -12 5 6 2 -1
-4 -8 -8 -10 -12 -8 -6 -6 -4
Sample Output
2
解题方法:参考PO爷的博客,OTZ PO爷
我们首先考虑如果在格子 a 修建一个抽水机,在什么情况下格子 b 的水也可以被抽干。我们可以发现当且仅当存在一条从 a 到 b 的路径,中间经过的抽水机(包括 a)的高度都不大于 b 的高度。因此我们可以考虑把所有格子的高度从小到大排序,我们把每一个格子建成一个集合。然后按照海拔高度从小到大扫描格子,对于当前的格子 i,我们找到所有与 i 相邻并且海拔高度不大于格子 i 的格子,我们发现如果这些格子中的任意一个洪水要是被解决了,那么格子 i 的洪水也可以被解决,所以我们合并这些格子。对于当前的格子 i,如果它必须被清理且与它相邻的格子集合中没有任何一个被清理,我们则把这个集合的清理状态标记为真,然后答案加 1。集合和每个格子是否被清理用并查集来维护就可以了。
代码如下:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1010;
int n, m, tot, ans, a[maxn][maxn];
int dir[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
struct node{
int x, y, height;
node(){}
node(int x, int y, int height) : x(x), y(y), height(height) {}
bool operator <(const node &rhs) const{
return height < rhs.height;
}
}city[maxn*maxn], maze[maxn*maxn];
bool flag[maxn][maxn];
pair <int, int> fa[maxn][maxn];
pair <int, int> find_set(pair <int, int> x){
if(x == fa[x.first][x.second] || fa[x.first][x.second] == make_pair(0, 0)) return fa[x.first][x.second] = x;
else return fa[x.first][x.second] = find_set(fa[x.first][x.second]);
}
void union_set(pair <int, int> x, pair <int, int> y){
x = find_set(x), y = find_set(y);
if(x != y){
fa[x.first][x.second] = y;
flag[y.first][y.second] |= flag[x.first][x.second];
}
}
void cha(int x, int y)
{
for(int i = 0; i < 4; i++){
int tx = x + dir[i][0], ty = y + dir[i][1];
if(tx <= 0 || ty <= 0 || tx > m || ty > n) continue;
if(a[tx][ty] > a[x][y]) continue;
union_set(make_pair(x, y), make_pair(tx, ty));
}
}
int main(){
scanf("%d%d", &m, &n);
for(int i = 1; i <= m; i++){
for(int j = 1; j <= n; j++){
scanf("%d", &a[i][j]);
if(a[i][j] > 0) city[++tot] = node(i, j, a[i][j]);
else{
a[i][j] = -a[i][j];
}
maze[i*n - n + j] = node(i, j, a[i][j]);
}
}
sort(city + 1, city + 1 + tot);
sort(maze + 1, maze + 1 + n * m);
for(int i = 1, j = 1; i <= tot; i++){
for(; j <= m*n && maze[j].height <= city[i].height; j++) cha(maze[j].x, maze[j].y);
pair <int, int> now = find_set(make_pair(city[i].x, city[i].y));
if(flag[now.first][now.second]) continue;
++ans, flag[now.first][now.second] = 1;
}
printf("%d\n", ans);
return 0;
}