95%的分很好拿,只要对每一个高度都跑一遍dfs/bfs就行了,但最后5%的分有难度。
首先我们可以知道,最外面一圈的高度和蓄水量,是固定的。我们可以考虑从外圈向内圈进行反向搜索操作。
用一个堆/优先队列作为搜索队列,维护已确定蓄水量的单元格中,高度+蓄水量最小的单元格。
每次取出堆顶元素,其周围的单元格高度为。
如果,必定可以将这个单元格填补到高度,总蓄水量增加,。
如果,那说明这个单元格无法蓄水,。
然后将新确定高度+蓄水量的单元格,压入堆中。
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1010;
int g[2][4]={{-1,0,0,1},{0,-1,1,0}};
int a[MAXN][MAXN],vis[MAXN][MAXN];
struct Node
{
int x,y,h;
Node(){ }
Node(int _x,int _y,int _h)
{
x=_x;
y=_y;
h=_h;
}
bool friend operator<(Node n1,Node n2)
{
return n1.h>n2.h;
}
};
priority_queue<Node> q;
int main()
{
int n,m,i,j;
Node now,nxt;
long long ans;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
scanf("%d",&a[i][j]);
for(i=1;i<=n;i++)
{
q.push(Node(i,1,a[i][1]));
q.push(Node(i,m,a[i][m]));
vis[i][1]=1;
vis[i][m]=1;
}
for(j=2;j<=m-1;j++)
{
q.push(Node(1,j,a[1][j]));
q.push(Node(n,j,a[n][j]));
vis[1][j]=1;
vis[n][j]=1;
}
ans=0;
while(!q.empty())
{
now=q.top();
q.pop();
for(i=0;i<4;i++)
{
nxt=Node(now.x+g[0][i],now.y+g[1][i],a[now.x+g[0][i]][now.y+g[1][i]]);
if(nxt.x<1||nxt.x>n||nxt.y<1||nxt.y>m||vis[nxt.x][nxt.y])
continue;
if(nxt.h<now.h)
{
ans+=now.h-nxt.h;
nxt.h=now.h;
}
q.push(nxt);
vis[nxt.x][nxt.y]=1;
}
}
printf("%lld\n",ans);
}