题目挺好的,不过自己不太会,用到优先队列的bfs,不错
解题思路:
- 给我们一个水池,我们想让里面的水最多,也就是慢慢找呗,
- 首先这个池子能存多少水(假设先是一圈墙),取决于这个墙的最低高度是多少,所以我们因此可以想到我们每次都是用最低的墙是进行搜索
- 首先我们利用贪心的思想,首先计算周围的墙(也就是最边上的墙),然后我们找高度最低的墙往里缩小(因此如果不找最小,如果水高于那个最小位置,那么水会溢出),所以从周围的最小值开始找起,如果找到比他高的,先暂时存入队列不用管,如果找到比他小的,那么证明这个比他小的位置可以储存水,因为周围都是比他高的(当前的值是周围的最小值),所以加上高度,然后把这个值变为围墙的最小值(这个地方好坑,一开始没注意),然后排着搜索就行,可以参照代码来看。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
typedef pair<int,pair<int,int>> PII;
typedef long long ll;
const int N = 1010;
bool st[N][N];
int ans[N][N];
int idx[4] = {0,0,1,-1}, idy[4] = {1,-1,0,0};
priority_queue<PII,vector<PII>,greater<PII>> q;
int main(){
int n, m;
scanf("%d%d",&n,&m);
for (int i = 1; i <= n;i ++){
for (int j = 1; j <= m; j++){
scanf("%d",&ans[i][j]);
if (i == 1 || j == 1 || i == n || j == m){
q.push({ans[i][j],{i,j}});
st[i][j] = true;
}
}
}
ll res = 0;
while(!q.empty()){
auto t = q.top();
q.pop();
int x = t.second.first;
int y = t.second.second;
for (int i = 0; i < 4 ; i++){
int xx = x + idx[i];
int yy = y + idy[i];
if (xx < 1 || xx > n || yy < 1 || yy > m || st[xx][yy]) continue;
st[xx][yy] = true;
if (t.first > ans[xx][yy]){
res += t.first - ans[xx][yy];
ans[xx][yy] = t.first;
}
q.push({ans[xx][yy],{xx,yy}});
}
}
printf("%lld\n",res);
return 0;
}