[10.10模拟] water

题意:

有一块矩形土地被划分成 n*m 个正方形小块。这些小块高低不平,每一小块都有自己的高度。水流可以由任意一块地流向周围四个方向的四块地中,但是不能直接流入对角相连的小块中。一场大雨后,由于地势高不同,许多地方都积存了不少降水。给定每个小块的高度,求每个小块的积水高度。注意:假设矩形地外围无限大且高度为 0。

题解:

思维

可以想象水就是每次从某个比较高的块上,流向别的比它低的块,直到把这个坑填满,我们称这个块为初始块......

而初始块应当是这个坑中周围一圈的块中的最小值,所以可以用堆来维护这个块

从初始块开始,流向所有比它低的块,直到把坑填满,若遇到了比它高的块,则这个块可能会成为另外一个坑的初始块,所以把它加入堆

每次从堆中弹出一个初始块,bfs把这个初始快能填的坑填满

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define ll long long
#define N 310
using namespace std;

int n,m;
int g[N][N],f[N][N],dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};
bool in[N][N],vis[N][N];

struct Node {
  int x,y,h;
  bool operator < (const Node &a) const {
    return h>a.h;
  }
};

priority_queue<Node> pq;
queue<pair<int,int> > q;

int gi() {
  int x=0,o=1; char ch=getchar();
  while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar();
  if(ch=='-') o=-1,ch=getchar();
  while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
  return o*x;
}

void bfs(int x, int y) {
  q.push(make_pair(x,y));
  while(!q.empty()) {
    int qx=q.front().first,qy=q.front().second;
    q.pop();
    for(int i=0; i<4; i++) {
      int xx=qx+dx[i],yy=qy+dy[i];
      if(!(xx>=1 && xx<=n && yy>=1 && yy<=m && !vis[xx][yy])) continue;
      vis[xx][yy]=1;
      if(f[x][y]>=f[xx][yy]) f[xx][yy]=f[x][y],q.push(make_pair(xx,yy));
      else pq.push((Node){xx,yy,f[xx][yy]});
    }
  }
}

int main() {
  n=gi(),m=gi();
  for(int i=1; i<=n; i++)
    for(int j=1; j<=m; j++)
      g[i][j]=gi(),f[i][j]=max(g[i][j],0);
  vis[1][1]=vis[1][m]=vis[n][1]=vis[n][m]=1;
  for(int i=2; i<n; i++) {
    pq.push((Node){i,1,f[i][1]});
    pq.push((Node){i,m,f[i][m]});
    vis[i][1]=vis[i][m]=1;
  }
  for(int i=2; i<m; i++) {
    pq.push((Node){1,i,f[1][i]});
    pq.push((Node){n,i,f[n][i]});
    vis[1][i]=vis[n][i]=1;
  }
  while(!pq.empty()) {
    Node now=pq.top();
    pq.pop();
    bfs(now.x,now.y);
  }
  for(int i=1; i<=n; i++) {
    for(int j=1; j<=m; j++)
      printf("%d ", f[i][j]-g[i][j]);
    printf("\n");
  }
  return 0;
}

转载于:https://www.cnblogs.com/HLXZZ/p/7648334.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值