zoukankan      html  css  js  c++  java
  • [POI2007]POW-The Flood

    [POI2007]POW-The Floodhttps://www.luogu.org/problemnew/show/P3457

    题目描述

    (AKD) 市处在一个四面环山的谷地里。最近一场大暴雨引发了洪水,(AKD) 市全被 水淹没了。(Blue Mary),(AKD) 市的市长,召集了他的所有顾问(包括你)参加一 个紧急会议。经过细致的商议之后,会议决定,调集若干巨型抽水机,将它们放 在某些被水淹的区域,而后抽干洪水。 你手头有一张 (AKD) 市的地图。这张地图是边长为 (m*n) 的矩形,被划分为 (m*n)(1*1) 的小正方形。对于每个小正方形,地图上已经标注了它的海拔高度以及它 是否是 (AKD) 市的一个组成部分。地图上的所有部分都被水淹没了。并且,由于 这张地图描绘的地面周围都被高山所环绕,洪水不可能自动向外排出。显然,我 们没有必要抽干那些非 (AKD) 市的区域。 每个巨型抽水机可以被放在任何一个 (1*1) 正方形上。这些巨型抽水机将持续地抽 水直到这个正方形区域里的水被彻底抽干为止。当然,由连通器原理,所有能向 这个格子溢水的格子要么被抽干,要么水位被降低。每个格子能够向相邻的格子 溢水,“相邻的”是指(在同一高度水平面上的射影)有公共边。

    输入格式:

    第一行是两个数 (m,n(1<=m,n<=1000)). 以下 (m) 行,每行 (n) 个数,其绝对值表示相应格子的海拔高度;若该数为正,表 示他是 (AKD) 市的一个区域;否则就不是。 请大家注意:所有格子的海拔高度其绝对值不超过 (1000),且可以为零.

    输出格式:

    只有一行,包含一个整数,表示至少需要放置的巨型抽水机数目

    输入样例:

    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

    输出样例:

    2


    贪心:
    将所有点按照海拔从小到大排序一遍,一个一个处理,将四周比它海拔低的[可以相等]用并查集并起来,在同一海拔的全部处理完毕后[比它高的地方有无抽水机对当前答案不产生影响],返回来判断每个属于(AKD)市的点所在的集合内是否有抽水机,没有则(Ans++)

    #define RG register
    #include<cstdio>
    #include<queue>
    #include<cmath>
    using namespace std;
    const int N=1005,NN=1e6+5;
    inline int read()
    {
        RG int x=0,w=1;RG char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*w;
    }
    int m,n,H=-1,Ans,cnt,l=1,r;//记录待处理的左右端点
    int A[4]={1,-1,0,0},B[4]={0,0,1,-1};
    int a[N][N],b[N][N],fa[NN];
    bool used[NN];
    struct node{
        int x,y,h;//横纵坐标,海拔高度
        bool c;//是否属于AKD市
    }undo[NN];
    bool operator < (node A,node B)//小根堆
    {
        return A.h>B.h;
    }
    priority_queue<node>Q;
    int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
    inline void unite(int x,int y)
    {
        x=find(x);
        y=find(y);
        if(x==y)return;
        fa[y]=x;
        if(used[y])used[x]=true;
    }
    int main()
    {
        n=read();
        m=read();
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
            {
                fa[m*(i-1)+j]=m*(i-1)+j;
                a[i][j]=read();
                b[i][j]=abs(a[i][j]);
                Q.push((node){i,j,b[i][j],a[i][j]>0});
            }
        Q.push((node){1e9,1e9,1e9,1});//在堆中加入val为inf的元素,否则高度最大的点集无法统计到答案
        while(!Q.empty())
        {
            node now=Q.top();Q.pop();
            cnt++;
            if(H<now.h)
            {
                H=now.h;
                r=cnt-1;
                for(int i=l;i<=r;i++)//统计答案
                {
                    int fi=find(m*(undo[i].x-1)+undo[i].y);
                    if(!used[fi]&&undo[i].c)Ans++,used[fi]=true;
                }
                l=cnt;
            }
            if(cnt==m*n+1)break;
            for(int i=0;i<4;i++)
            {
                int xx=now.x+A[i],yy=now.y+B[i];
                if(xx<1||xx>n||yy<1||yy>m)continue;
                if(b[xx][yy]<=now.h)unite(m*(xx-1)+yy,m*(now.x-1)+now.y);//并查集
            }
            undo[cnt]=now;//放入undo数组,表示待查询
        }
        printf("%d
    ",Ans);
        return 0;
    }
    
  • 相关阅读:
    子网划分
    数据报分片
    CRC校验
    内部网关协议RIP与OSPF的特点、区别
    简述协议与服务的区别、关系
    算法思想
    上机实验题7--求解装载问题
    上机实验题6--求最长单调递增子序列
    python进程和线程
    python序列化操作
  • 原文地址:https://www.cnblogs.com/sdzwyq/p/8468930.html
Copyright © 2011-2022 走看看