[10.10模拟] water
题意:
有一块矩形土地被划分成 n*m 个正方形小块。这些小块高低不平,每一小块都有自己的高度。水流可以由任意一块地流向周围四个方向的四块地中,但是不能直接流入对角相连的小块中。一场大雨后,由于地势高不同,许多地方都积存了不少降水。给定每个小块的高度,求每个小块的积水高度。注意:假设矩形地外围无限大且高度为 0。
题解:
思维
可以想象水就是每次从某个比较高的块上,流向别的比它低的块,直到把这个坑填满,我们称这个块为初始块......
而初始块应当是这个坑中周围一圈的块中的最小值,所以可以用堆来维护这个块
从初始块开始,流向所有比它低的块,直到把坑填满,若遇到了比它高的块,则这个块可能会成为另外一个坑的初始块,所以把它加入堆
每次从堆中弹出一个初始块,bfs把这个初始快能填的坑填满
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define ll long long
#define N 310
using namespace std;
int n,m;
int g[N][N],f[N][N],dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};
bool in[N][N],vis[N][N];
struct Node {
int x,y,h;
bool operator < (const Node &a) const {
return h>a.h;
}
};
priority_queue<Node> pq;
queue<pair<int,int> > q;
int gi() {
int x=0,o=1; char ch=getchar();
while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar();
if(ch=='-') o=-1,ch=getchar();
while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
return o*x;
}
void bfs(int x, int y) {
q.push(make_pair(x,y));
while(!q.empty()) {
int qx=q.front().first,qy=q.front().second;
q.pop();
for(int i=0; i<4; i++) {
int xx=qx+dx[i],yy=qy+dy[i];
if(!(xx>=1 && xx<=n && yy>=1 && yy<=m && !vis[xx][yy])) continue;
vis[xx][yy]=1;
if(f[x][y]>=f[xx][yy]) f[xx][yy]=f[x][y],q.push(make_pair(xx,yy));
else pq.push((Node){xx,yy,f[xx][yy]});
}
}
}
int main() {
n=gi(),m=gi();
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++)
g[i][j]=gi(),f[i][j]=max(g[i][j],0);
vis[1][1]=vis[1][m]=vis[n][1]=vis[n][m]=1;
for(int i=2; i<n; i++) {
pq.push((Node){i,1,f[i][1]});
pq.push((Node){i,m,f[i][m]});
vis[i][1]=vis[i][m]=1;
}
for(int i=2; i<m; i++) {
pq.push((Node){1,i,f[1][i]});
pq.push((Node){n,i,f[n][i]});
vis[1][i]=vis[n][i]=1;
}
while(!pq.empty()) {
Node now=pq.top();
pq.pop();
bfs(now.x,now.y);
}
for(int i=1; i<=n; i++) {
for(int j=1; j<=m; j++)
printf("%d ", f[i][j]-g[i][j]);
printf("\n");
}
return 0;
}