Jzoj P5830 water

Description

有一块矩形土地被划分成 n*m 个正方形小块。这些小块高低不 平,每一小块都有自己的高度。水流可以由任意一块地流向周围四个 方向的四块地中,但是不能直接流入对角相连的小块中。 一场大雨后,由于地势高低不同,许多地方都积存了不少降水。 给定每个小块的高度,求每个小块的积水高度。 注意:假设矩形地外围无限大且高度为 0。

Input

第一行包含两个非负整数 n,m。 接下来 n 行每行 m 个整数表示第 i 行第 j 列的小块的高度。
Output
输出 n 行,每行 m 个由空格隔开的非负整数,表示每个小块的积 水高度。

Sample Input

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

Sample Output

0 0 0
0 1 0
0 0 1 

Data Constraint

对于 20%的数据 n,m<=4
对于 40%的数据 n,m<=15
对于 60%的数据 n,m<=50
对于 100%的数据 n,m<=300,|小块高度|<=10^9。
在每一部分数据中,均有一半数据保证小块高度非负

Solution

首先将所有小于0的补为0,将边上一圈作为边界放入堆,然后向内拓展,因为每次都是取最矮的边界,所以是正确的,且每块地只被更新一次
代码中有注释,或许可以解决一些问题

#include <cstdio>
#include <algorithm>
#include <queue>
#include <cmath>
#include <cstring>
using namespace std;
const int maxn=300+5;
int n,m;
int h[maxn][maxn];
int ans[maxn][maxn];
bool vis[maxn][maxn];
int dx[]={0,-1,0,0,1};
int dy[]={0,0,-1,1,0};
struct Node{
	int x,y,val;
	Node(){}
	Node(int _x,int _y,int _val){
		x=_x,y=_y,val=_val;
	}
	bool operator < (const Node &B)const{
		return val>B.val;
	}
};
priority_queue <Node> q;
int main(){
	//freopen("1.in","r",stdin);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i){
		for(int j=1;j<=m;++j){
			scanf("%d",&h[i][j]);
			if(h[i][j]<0) ans[i][j]+=(-h[i][j]),h[i][j]=0; //先填为0,好处理,因为最后至少是0
			if(i==1||i==n||j==1||j==m) q.push(Node(i,j,h[i][j])),vis[i][j]=1;//将出口入堆
		}
	}
	int x,y,val;
	while(!q.empty()){
		x=q.top().x; y=q.top().y; val=q.top().val; q.pop();
		for(int i=1,rx,ry;i<=4;++i){
			rx=x+dx[i]; ry=y+dy[i];
			if(vis[rx][ry] || rx<1 || rx>n || ry<1 || ry>m) continue; //目标点不合法或已搜过
			if(val>h[rx][ry]) ans[rx][ry]+=(val-h[rx][ry]); //目标点比当前低,累加答案
			vis[rx][ry]=1;
			q.push(Node(rx,ry,max(h[rx][ry],val)));// 向内拓展,不用担心取max会使结果错误,因为每次从堆中取的点都是最低的
		}
	}
	for(int i=1;i<=n;++i){
		for(int j=1;j<=m;++j){
			printf("%d ",ans[i][j]);
		}
		printf("\n");
	}
	return 0;
}

posted @ 2020-08-01 16:39  liuzhaoxu  阅读(117)  评论(0编辑  收藏  举报