[POI1999]降水

题目

原题地址

解说

由于下的雨很大,我们可以把这道题理解为雨水先把每一块土地都充填到了最大高度那么高,然后开始从四周泄洪。只要确定了这个思路,按照它来模拟就可以,即先把除了四边上所有位置的高度全部设定为最大高度,之后开一个按照高度由小到大进行排序的小跟堆,从四周开始BFS,一旦遇到水的高度比自己还要高的位置,就将其泄洪。最后的答案就是所有位置水的高度减原高度的和。

具体的一些实现过程详见代码注释。

代码

#include<bits/stdc++.h>
using namespace std;
const int lzw=100+3;
int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};
int a[lzw][lzw],n,m,ans[lzw][lzw],solve[lzw][lzw],maxx,cnt;
char buf[1<<20], *p1, *p2;
char gc() { 
    if (p1 == p2) {
        p1 = buf;
        p2 = buf + fread(buf, 1, 1<<20, stdin);
    }
    return *p1++;
}
inline int read(){
    int f = 1, x = 0;
    char c = gc();
	while (c < '0' || c > '9') {
	    if (c == '-') f = -1;
	    c = gc();
	}
	while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc();
	return f * x;
}
struct node{
	int x,y,h;
	node(){}
	node(int xx,int yy,int hh){
		x=xx;
		y=yy;
		h=hh;
	}
	bool operator < (const node &A) const{
		return h>A.h;
	}
}all[4*lzw];
int main(){
	n=read(); m=read();
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			a[i][j]=read();
			solve[i][j]=a[i][j];
			maxx=max(maxx,a[i][j]);//记录最高峰
			if(i==1||i==n||j==1||j==m) all[++cnt]=node(i,j,a[i][j]);
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if((i==1||i==n||j==1||j==m)&&a[i][j]>=0) continue;
			if((i==1||i==n||j==1||j==m)&&a[i][j]<0) solve[i][j]=0;//四周设为0
			if(i!=1&&i!=n&&j!=1&&j!=m)solve[i][j]=maxx;//如果目前的位置不在四边上则全部充填为最大水位
		}
	}
	priority_queue<node> q;//按照高度排序的小根堆
	for(int i=1;i<=cnt;i++) q.push(all[i]);//先把四周入队
	while(!q.empty()){//BFS
		node k=q.top();
		q.pop();
		for(int i=0;i<4;i++){
			int xx=k.x+dx[i],yy=k.y+dy[i];
			if(xx<1||yy<1||xx>n||yy>m) continue;
			if(solve[xx][yy]<=solve[k.x][k.y]) continue;//到达的点还不如(x,y)水位高则说明无法从这里泄洪,直接跳过
			if(solve[k.x][k.y]>a[xx][yy]){//到达的点水位更高但原高度比现在水位低则泄洪为现在水位
				solve[xx][yy]=solve[k.x][k.y];
				q.push(node(xx,yy,solve[xx][yy]));
			}
			if(solve[k.x][k.y]<=a[xx][yy]){//到达的点水位更高但原高度比现在水位高则泄洪为原高度
				solve[xx][yy]=a[xx][yy];
				q.push(node(xx,yy,solve[xx][yy]));
			}
		}
	}
	int ans=0;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			ans+=solve[i][j]-a[i][j];
	printf("%d\n",ans);
	return 0;
}

幸甚至哉,歌以咏志。

签名: 我将轻轻叹息,叙述这一切, 许多许多年以后: 林子里有两条路,我—— 选择了行人稀少的那一条, 它改变了我的一生。
posted @ 2020-08-01 17:13  DarthVictor  阅读(118)  评论(0编辑  收藏  举报
莫挨老子!