分析
对于每一个位置,它的积水能否达到某一个高度,要求的便是它附近是否有完全封闭的由原高度大于等于该高度的位置连线组成的封闭图形。
所以我们便枚举每一次所需达到的高度,看有多少个比该高度低的能达到该高度,我们发现需要在整个图形上去掉两类,一是原来就比它高的,二是在所有封闭图形外的点。于是考虑 \(dfs\) 来处理这个问题。答案先加上总点数,每个大于等于枚举高度的点对答案减一,在进行 \(dfs\),如若搜索到小于等于当前枚举的高度的点,也减一,每当搜索到大于等于枚举高度的点,则返回,不能搜到的,就可以被理解为用墙围起来的部分,这样就行了。
时间复杂度是 \(10^8\),但因为\(dfs\) 本身会枚举到很多重点,所以会稍微超出时间限制,可以用 \(bfs\),用两个队列交替进行,每次用一个队列时在另一个队列存上这一次所寻到的的边界来优化这一进程,这里放上用 \(O2\) 过的 \(dfs\) 代码。
代码
#include<bits/stdc++.h>
using namespace std;
int h[105][105],vis[105][105];
int T;
int n,m;
int mx,mn;
int ans,sum;
inline void read(int &res){
char c;
int f=1;
res=0;
c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9')res=(res<<1)+(res<<3)+c-48,c=getchar();
res*=f;
}
int H;
void dfs(int x,int y){
if(x<0||y<0||x>n+1||y>m+1)return;
if(vis[x][y])return;
if(h[x][y]>=H)return;
vis[x][y]=1;
if(x>0&&x<=n&&y>0&&y<=m)sum--;
dfs(x-1,y);
dfs(x+1,y);
dfs(x,y-1);
dfs(x,y+1);
}
int t[10005];
int main(){
read(n);read(m);
mn=10005;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
read(h[i][j]);
mx=max(mx,h[i][j]);
mn=min(mn,h[i][j]);
t[h[i][j]]++;
}
}
for(int i=mx;i>=mn;i--){
t[i]+=t[i+1];//高度大于等于i的数量
}
for(H=mn+1;H<=mx;H++){//枚举所要到达的高度
memset(vis,0,sizeof(vis));
sum=n*m-t[H];
dfs(0,0);
if(!sum)break;//没位置能向上了
ans+=sum;
}
cout<<ans<<endl;
return 0;
}