并查集 [POI2007]洪水pow

 

问题 E: [POI2007]洪水pow

时间限制: 5 Sec  内存限制: 128 MB

题目描述

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

提示

    其实能够证明,放在城市一定最优。。从最低的地点开始处理,因为抽水机建的越低一定最优。用一个p[]数组记录这个点是不是已经能被抽水了。在遍历的时候,找这个点四周已被标记的点(说白了就是比他低的),合并为自己的父亲,看能否连上。在每搜完一个高度以后,找刚刚遍历的点,看是否有没联通的城市,如果有那他就得建抽水机了。(不能最后判断,不然高地势会把连不上的低地势连上的)
   
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int n,m,cnt,ans;
struct city
{
    int h,id;
     friend bool operator <( city a, city b){return a.h<b.h;}
}a[1000005];
int f[1000005],vis[10000005],id[1005][1005],v[1000005];
int p[1000005],t2[4][2]={{-1,0,},{0,-1,},{0,1,},{1,0,},};
int find(int x)
{
    if(f[x]!=x)f[x]=find(f[x]);
    return f[x];
}
void get(int g)
{
    int k=a[g].id;int x=(k-1)/m+1,y=(k-1)%m+1;
    for(int i=0;i<4;i++)
    {   
        int x1=x+t2[i][0],y1=y+t2[i][1];
        if(x1>=1&&x1<=n&&y1>=1&&y1<=m)
        {
            int l=id[x1][y1];
            if(vis[l])
            {
                 int fx=find(l);
                 p[k]=(p[k]||p[fx]);
                 f[fx]=find(k);
            }
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
       for(int j=1;j<=m;j++)
       {
            scanf("%d",&a[++cnt].h);
            id[i][j]=cnt;
            if(a[cnt].h>0)v[cnt]=1;
            else a[cnt].h=abs(a[cnt].h);
            //v[i][j]=a[cnt].h;
            a[cnt].id=cnt;
            f[cnt]=cnt;
       }
    sort(a+1,a+cnt+1);
    int last=1;
    for(int i=1;i<=cnt;i++)
    {
        get(i);
        vis[a[i].id]=1;
        if(a[i+1].h!=a[i].h)
        {
            for(int j=last;j<=i;j++)
            {
                int k=a[j].id;
                if(v[k]&&!p[find(k)])
                {
                    ans++;
                    p[find(k)]=1;
                }           
            }
            last=i+1;
        }
    }
    cout<<ans;
}

原文地址:https://www.cnblogs.com/QTY2001/p/7632709.html