zoukankan      html  css  js  c++  java
  • 洪水[POI2007]

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

    题目描述

    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


    题解
    看了好久的样例也没弄明白2是怎么得出来的,后来读了好几遍题才大概弄明白他想表达些什么,这种神奇的情况不知道是题目本来就这样还是翻译的问题……首先,给出来的是地图不是水位图,而且正负只表类型绝对值才是海拔;其次,整个地图都被水淹没,可以想象一下刚开始的洪水高千尺手可摘星辰smg;最后,抽水是把所有和它联通的比较高的水从高不见顶(雾)抽到尽量低的水平面上,比如说545532,在2放一个抽水机,除了4之外所有的水都会被抽干,而4上面的水其实也是5的高度,需要联系现实想象一下(从一片海变成一个一个小水坑)。题目中的要求是把城市的水抽干,所以山地是可以有存水的。
    理解了题意,并查集的思路也很自然了。首先明确一点:虽然把抽水机放在山地也合法,但是并不会比放在城市里更优。因此,我们直接从低到高枚举城市,因为越低的城市越没有别的城市能抽干它的水。每次枚举一个城市,都把比它更低或同等高度的所有点(包括山地和城市)和这些点周围high<=它的点合并,最后看本城市所在的集合是否已经被安装了抽水机;如果没有,把ans++。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    const int sj=1005;
    int sz[sj][sj],f[sj*sj],cnt,cou,cs,now=1,xd,yd;
    int ans,a[sj][sj],n,m;
    bool s[sj*sj];
    struct D
    {
        int x,y,num;
    }d[sj*sj],c[sj*sj];
    int find(int x)
    {
        if(f[x]==-1) return x;
        f[x]=find(f[x]);
        return f[x];
    }
    void hb(int x,int y)
    {
        x=find(x),y=find(y);
        if(x!=y)
        { 
           f[x]=y;
           s[y]|=s[x];
        }
    }
    int comp(const D&a,const D&b)
    {
        return a.num<b.num;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
          for(int j=1;j<=m;j++)
          {
             scanf("%d",&cs);
             a[i][j]=abs(cs);
             sz[i][j]=++cnt;
             d[cnt].x=i;
             d[cnt].y=j;
             d[cnt].num=abs(cs);
             if(cs>0)  c[++cou]=d[cnt];
          }
        memset(f,-1,sizeof(f));
        sort(c+1,c+cou+1,comp);
        sort(d+1,d+cnt+1,comp);
        for(int i=1;i<=cou;i++)
        {
            while(d[now].num<=c[i].num&&now<=cnt)
            {
               xd=d[now].x,yd=d[now].y;
               if(xd!=1&&a[xd-1][yd]<=a[xd][yd])
                  hb(sz[xd][yd],sz[xd-1][yd]);
               if(yd!=1&&a[xd][yd-1]<=a[xd][yd])
                  hb(sz[xd][yd],sz[xd][yd-1]);
               if(xd!=n&&a[xd+1][yd]<=a[xd][yd])
                  hb(sz[xd][yd],sz[xd+1][yd]);
               if(yd!=m&&a[xd][yd+1]<=a[xd][yd])
                  hb(sz[xd][yd],sz[xd][yd+1]);
               now++;
            }
            xd=c[i].x,yd=c[i].y;
            if(!s[find(sz[xd][yd])])
            {
               s[find(sz[xd][yd])]=1;
               ans++;
            }
        }
        printf("%d",ans);
        return 0;
    }
    pow
     
  • 相关阅读:
    VS2010 自动跳过代码现象
    Reverse Linked List II 【纠结逆序!!!】
    Intersection of Two Linked Lists
    Linked List Cycle II
    Remove Nth Node From End of List 【另一个技巧,指针的指针】
    Swap Nodes in Pairs
    Merge Two Sorted Lists
    Remove Duplicates from Sorted List
    Linked List Cycle
    Dungeon Game
  • 原文地址:https://www.cnblogs.com/moyiii-/p/7360115.html
Copyright © 2011-2022 走看看