【POI1999&&codevs3634】积水,关于sunshine爷的NOIP(suan)水(ge)题(pi)赛

3634 积水(POI1999)
时间限制: 1 s
空间限制: 1000 KB
题目等级 : 大师 Master
题解
查看运行结果
题目描述 Description
有这样一块土地,它可以被划分N*M个正方形小块,每块面积是一平方英寸,第i行第j列的小块可以表示成P(i,j)。这块土地高低不平,每一小块地P(i,j)都有自己的高度H(i,j)(单位是英寸)。

一场倾盆大雨后,由于这块地地势高低不同,许多低洼地方都积存了不少降水。假如你已经知道这块土地的详细信息,你能求出它最多能积存多少立方英寸的降水么?

输入描述 Input Description
输入文件的第一行是两个正整数n和m,1<=n<=100,1<=m<=100,表示土地的尺寸。下面n行,每行m个整数(1..10000);第j行第i个数表示第j行第i列立方体的高。

输出描述 Output Description
输出文件只有一个数,表示在这个建筑上可以聚合的积水的最大值

样例输入 Sample Input

3 6
3 3 4 4 4 2
3 1 3 2 1 4
7 3 1 6 4 1

样例输出 Sample Output
5

数据范围及提示 Data Size & Hint
见输入描述
写在前面:继CA爷出完题虐过我们以后,sunshine爷也来跟风,结果我很没有意外的被虐杀了(CA爷的题目好歹还能用暴力得分啊啊啊啊)
——————————————————————————————————————————————
解题思路:刚开始我的想法是广搜(事实证明我的这一步思路没有问题),然后就是找出所有高于的点blabla,但是我跟傻~逼一样不加尾指针,并且我的想法就是错误的。后来我看了一下XYX大爷的程序,又问了一下ShallWe大爷解题原理,然后终于写出来了╮(╯▽╰)╭
基本的想法就是从1开始到最高高度,一层层灌水,看看能积攒多少水,把不能积水的点去掉,就是这一高度水下能积累的点,类似于细胞的做法
代码:

#include<cstdio>
#include<iostream>
using namespace std;
int n,m,a[301][301],flag[301][301],fl[4],num;
//稍稍开大一点,可以防止越界(其实并没有什么用,102足以
struct os
{
    int x,y;
}team[20001];//这里也可以用两个数组来分别表示横纵坐标
main()
{
    int maxn=0;
    int ans=0;
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++)
    for (int j=1;j<=m;j++)
    {
        scanf("%d",&a[i][j]);
        maxn=max(maxn,a[i][j]);
    }
    for (int i=1;i<=maxn;i++)
    {
        int head=1,tail=1;num=1;
        for (int j=0;j<=n+1;j++)
        for (int k=0;k<=m+1;k++)
        if (a[j][k]<i) flag[j][k]=0;//能存水
        else {flag[j][k]=1;num++;}//不能存水
        team[1].x=0;
        team[1].y=0;//从(0,0)开始搜索,找出所有不能存水的点(其实我刚开始也是找不能存水的点,但是是直接找并不是逐层找,所以就不知道怎么判断内部的点(只是找出边界及边界所扩展的不能存水的点)
    while (head<=tail)
    {
        flag[team[head].x][team[head].y]=1;
        if (team[head].y-1>=0)
        if (flag[team[head].x][team[head].y-1]==0)
        {flag[team[head].x][team[head].y-1]=1;tail++;team[tail].x=team[head].x;team[tail].y=team[head].y-1;num++;}
        if (team[head].y+1<=m+1)
        if (flag[team[head].x][team[head].y+1]==0)
        {flag[team[head].x][team[head].y+1]=1;tail++;team[tail].x=team[head].x;team[tail].y=team[head].y+1;num++;}
        if (team[head].x-1>=0)
        if (flag[team[head].x-1][team[head].y]==0)
        {flag[team[head].x-1][team[head].y]=1;tail++;team[tail].x=team[head].x-1;team[tail].y=team[head].y;num++;}
        if (team[head].x+1<=n+1)
        if (flag[team[head].x+1][team[head].y]==0)
        {flag[team[head].x+1][team[head].y]=1;tail++;team[tail].x=team[head].x+1;team[tail].y=team[head].y;num++;}
        head++;
    }
    ans=ans+(n+2)*(m+2)-num;//num这里是不能存水的点,因为算上了边界,n,m所以要加2
    }   
    printf("%d",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值