water

问题 B: water
时间限制: 1 Sec 内存限制: 256 MB
题目描述
有一块矩形土地被划分成 n*m 个正方形小块。这些小块高低不平,每一小块都有自己的高度。水流可以由任意一块地流向周围四个方向的四块地中,但是不能直接流入对角相连的小块中。
一场大雨后,由于地势高低不同,许多地方都积存了不少降水。给定每个小块的高度,求每个小块的积水高度。
注意:假设矩形地外围无限大且高度为0。
输入
第一行包含两个非负整数n,m。
接下来n 行每行m 个整数表示第i 行第j 列的小块的高度。
输出
输出n 行,每行m 个由空格隔开的非负整数,表示每个小块的积水高度。
样例输入
3 3
4 4 0
2 1 3
3 3 -1
样例输出
0 0 0
0 1 0
0 0 1
提示
对于20%的数据 n,m<=4

对于40%的数据 n,m<=15

对于60%的数据 n,m<=50

对于100%的数据 n,m<=300,|小块高度|<=10^9。

在每一部分数据中,均有一半数据保证小块高度非负

其实我们要求的是某个点到边界的路径中最大高度的最小值。因为一条路径能盛水的最大高度就是这条路径的上的最大高度,最终某个点能盛水的高度是所有路径上最高高度的最小值。所以可以跑spfa,求出这个,就能算出盛水的高度了。

#pragma GCC optimize("O3")
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#define N 300005
#define inf 1000000000
#define ll long long
using namespace std;
int read()
{
    int sum=0,f=1;char x=getchar();
    while(x<'0'||x>'9'){if(x=='-')f=-1;x=getchar();}
    while(x>='0'&&x<='9'){sum=(sum<<1)+(sum<<3)+x-'0';x=getchar();}
    return sum*f;
}
struct node
{
    int x,y;
    node(){}
    node(int x_,int y_){x=x_,y=y_;}
};
int n,m;int vis[304][304];
ll a[304][304],dis[305][305];
int wz[4][2]={0,1,0,-1,1,0,-1,0};
queue<node> q;
void spfa()
{
    while(!q.empty())
    {
        node x=q.front();q.pop();vis[x.x][x.y]=0;
        for(int i=0;i<4;i++)
        {
            node to;to.x=x.x+wz[i][0],to.y=x.y+wz[i][1];
            if(to.x<=1||to.x>=n||to.y>=m||to.y<=1)continue;
            int k=max(a[to.x][to.y],dis[x.x][x.y]);
            if(dis[to.x][to.y]>k)
            {
                dis[to.x][to.y]=k;
                if(!vis[to.x][to.y]){vis[to.x][to.y]=1;q.push(to);}
            }
        }
    }
}
int main()
{
    memset(dis,120,sizeof(dis));
    n=read();m=read();
    for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)a[i][j]=read();
    for(int i=1;i<=n;i++)
    {
        dis[i][1]=max(0ll,a[i][1]);
        dis[i][m]=max(0ll,a[i][m]);
        q.push(node(i,1));q.push(node(i,m));
        vis[i][1]=vis[i][m]=1;
    }
    for(int i=1;i<=m;i++)
    {
        dis[1][i]=max(0ll,a[1][i]);
        dis[n][i]=max(0ll,a[n][i]);
        q.push(node(1,i));q.push(node(n,i));
        vis[1][i]=vis[n][i]=1;
    }
    spfa();
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            int k=max(0ll,dis[i][j]-a[i][j]);
            printf("%d ",k);
        }
        printf("\n");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值