​传送门​

题目大意

一个矩形区域,高低起伏,求最多储水量。(边界不能储水)

思路

先将边界加入优先队列,每次取高度最小的点,找与其相邻且未访问过的点,若邻点高度大于等于它,直接加入优先队列更新边界,否则更新答案,并将邻点的高度置为该点高度,然后加入优先队列更新边界。

代码

struct node{
int x;
int y;
ll h;
bool operator<(const node X) const{
return h > X.h;
}
};
int n,m;
ll a[500][500];
int vis[500][500];
priority_queue<node>q;

int dx[5] = {0,0,1,0,-1};
int dy[5] = {0,1,0,-1,0};//四个方向

void bfs(){
ll ans=0;
while(!q.empty()){
node tmp=q.top();
q.pop();
for(int i=1;i<=4;i++){
int nx=tmp.x+dx[i];
int ny=tmp.y+dy[i];
if(nx<=1||nx>=n||ny<=1||ny>=m||vis[nx][ny]){//越界或者被标记过
continue;
}
vis[nx][ny]=1;
if(a[nx][ny]>=tmp.h){//比边界大,就不能存水,更新
node tmp2(nx,ny,a[nx][ny]);
q.push(tmp2);
}
else{
ans+=tmp.h-a[nx][ny];
node tmp2(nx,ny,tmp.h);
q.push(tmp2);//比边界小,更新答案,但是高度仍然继承上一个
}
}
}
printf("%lld\n",ans);
}

int main(){
scanf("%d%d",&m,&n);
memset(vis,0,sizeof vis);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%lld",&a[i][j]);
if(i==1||j==1||i==n||j==m){
node tmp(i,j,a[i][j]);
q.push(tmp);
vis[i][j]=1;
}
}
}
bfs();
return 0;
}