[BZOJ]1104: [POI2007]洪水pow

7 篇文章 0 订阅

Description
  AKD市处在一个四面环山的谷地里。最近一场大暴雨引发了洪水,AKD市全被水淹没了。Blue Mary,AKD市的市长,召集了他的所有顾问(包括你)参加一个紧急会议。经过细致的商议之后,会议决定,调集若干巨型抽水机,将它们放在某些被水淹的区域,而后抽干洪水。你手头有一张AKD市的地图。这张地图是边长为m*n的矩形,被划分为m*n个1*1的小正方形。对于每个小正方形,地图上已经标注了它的海拔高度以及它是否是AKD市的一个组成部分。地图上的所有部分都被水淹没了。并且,由于这张地图描绘的地面周围都被高山所环绕,洪水不可能自动向外排出。显然,我们没有必要抽干那些非AKD市的区域。每个巨型抽水机可以被放在任何一个1*1正方形上。这些巨型抽水机将持续地抽水直到这个正方形区域里的水被彻底抽干为止。当然,由连通器原理,所有能向这个格子溢水的格子要么被抽干,要么水位被降低。每个格子能够向相邻的格子溢水,“相邻的”是指(在同一高度水平面上的射影)有公共边。
Input
  第一行是两个数m,n(1<=m,n<=1000). 以下m行,每行n个数,其绝对值表示相应格子的海拔高度;若该数为正,表示他是AKD市的一个区域;否则就不是。请大家注意:所有格子的海拔高度其绝对值不超过1000,且可以为零.
Output
  只有一行,包含一个整数,表示至少需要放置的巨型抽水机数目。
Sample Input
6 9
-2 -2 -1 -1 -2 -2 -2 -12 -3
-2 1 -1 2 -8 -12 2 -12 -12
-5 3 1 1 -12 4 -6 2 -2
-5 -2 -2 2 -12 -3 4 -3 -1
-5 -6 -2 2 -12 5 6 2 -1
-4 -8 -8 -10 -12 -8 -6 -6 -4
Sample Output
2

对于一个海拔为x的点,如果与它相邻的点中有一个海拔小于等于x的点能被抽干,那么它也可以一同被抽干。很容易就能想到并查集,我们把一堆可以用一个抽水机解决的点连在一起,最后看要用多少个就好了。

#include <cstdio>
#include <algorithm>
using namespace std;
inline char tc(void)
{
    static char fl[100000],*A=fl,*B=fl;
    return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
}
inline int read(void)
{
    int a=0,f=1;static char c;
    while((c=tc())<'0'||c>'9')c=='-'?f=-1:0;
    while(c>='0'&&c<='9')
        a=a*10+c-'0',c=tc();
    return a*f;
}
int n,m,tot,cnt,f[1000001],map[1002][1002],ans,dx[]={1,-1,0,0},dy[]={0,0,1,-1},x,y,_x,_y,t,o;
struct Y
{
    int x,y,h;
    bool operator <(const Y&a) const
    {
        return h<a.h;
    }
}city[1000001],s[1000001];
char have[1000001];
int find(int x)
{
    return f[x]==x?x:f[x]=find(f[x]);
}
int main(void)
{
    register int i,j,l;
    n=read(),m=read();
    for (i=1;i<=n;++i)
        for (j=1;j<=m;++j)
            f[(i-1)*m+j]=(i-1)*m+j,x=read(),x>0?(city[++cnt].x=i,city[cnt].y=j,city[cnt].h=x,s[++tot].x=i,s[tot].y=j,s[tot].h=x,map[i][j]=x):(s[++tot].x=i,s[tot].y=j,s[tot].h=-x,map[i][j]=-x);
    for (i=0;i<=n+1;i++)
        map[i][0]=map[i][m+1]=2e9;
    for (i=0;i<=m+1;i++)
        map[0][i]=map[n+1][i]=2e9;
    sort(city+1,city+cnt+1),sort(s+1,s+tot+1);  //按海拔从小到大进行操作
    for (i=1,j=1;i<=cnt;++i)
    {
        for (;j<=n*m&&s[j].h<=city[i].h;++j)
        {
            x=s[j].x,y=s[j].y,t=(x-1)*m+y;
            for (l=0;l<4;++l)
            {
                _x=x+dx[l],_y=y+dy[l],o=(_x-1)*m+_y;
                if(map[_x][_y]<=map[x][y])   
                    have[find(t)]|=have[find(o)],f[find(o)]=find(t);//以海拔较高的点作为父节点,这一过程中城市节点的海拔最高,能便于之后打have标记 
            }
        }
        if(!have[find((city[i].x-1)*m+city[i].y)])      
            ++ans,have[find((city[i].x-1)*m+city[i].y)]=1;//对以这个城市节点为父节点的并查集打上have标记 
    }
    printf("%d",ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值