码迷,mamicode.com
首页 > 其他好文 > 详细

[POI2007]POW-The Flood

时间:2018-02-25 13:07:55      阅读:152      评论:0      收藏:0      [点我收藏+]

标签:for   names   while   uri   use   高度   namespace   否则   etc   

[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\n",Ans);
    return 0;
}

[POI2007]POW-The Flood

标签:for   names   while   uri   use   高度   namespace   否则   etc   

原文地址:https://www.cnblogs.com/sdzwyq/p/8468930.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!