2017.8.13 [POI2007]洪水pow 并查集 (题意比较难理解)

题目描述

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,且可以为零.

输出

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

solution

题意理解

一开始洪水把图全淹了
洪水并不是只能向四周流,直到四周的高度,(题中的降到水平线即是这个意思)
负的海拔不是真的负,只是为了标记一下非城市.....
题中是一个很真实的山地....

我们考虑每一个城市的水被排完,当且仅当此城市有抽水机 OR 与它有有一条水能流过去的路径的点装了抽水机

所以可以在某几个点放抽水机,而所有城市节点都被抽光

而一个城市的水被抽光,一定是high<=它的点放了抽水机

所以把每一个点的海拔从小到大排序

从小到大遍历城市节点的同时

遍历所有节点,把high<=当前城市节点的点 与其周围的比它低的点 连起来(这样可以保证某一个点被围起来就不会对其他点做出贡献)

用并查集来维护

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<iostream>
 5 #define mem(a,b) memset(a,b,sizeof(a))
 6 using namespace std;
 7 const int N=1006;
 8 
 9 struct son
10 {
11     int x,y,val;
12     friend bool operator < (son a,son b)
13     {
14         return a.val<b.val;
15     }
16 };
17 son ji[N*N];
18 int n,m,ans;
19 int h[N][N],ha[N][N];
20 
21 int fa[N*N],flag[N*N];
22 int fin(int x)
23 {
24     if(fa[x]==-1)
25       return x;
26     return fa[x]=fin(fa[x]);
27 }
28 void match(int u,int v)
29 {
30     int x=fin(u),y=fin(v);
31     if(x!=y)
32     {
33         fa[x]=y;
34         flag[y]|=flag[x];
35     }
36 }
37 
38 void out11()
39 {
40     printf("
");
41     for(int i=1;i<=n;++i)
42     {
43         for(int j=1;j<=m;++j)
44           printf("%d ",ha[i][j]);
45         printf("
");
46     }
47     printf("
");
48 }
49 
50 int main(){
51     
52     //freopen("1.txt","r",stdin);
53     
54     mem(fa,-1);
55     
56     scanf("%d%d",&n,&m);
57     for(int i=1;i<=n;++i)
58       for(int j=1;j<=m;++j)
59       {
60             scanf("%d",&h[i][j]);
61             ha[i][j]=(i-1)*m+j;
62             ji[ha[i][j]]=(son){i,j,abs(h[i][j])};
63         }
64     sort(ji+1,ji+1+n*m);
65     //out11();
66     son temp;
67     int now=1;
68     for(int sss=n*m,i=1;i<=sss;++i)
69     {
70         if(h[ji[i].x][ji[i].y]<=0)
71           continue;
72         while(ji[now].val<=ji[i].val&&now<=sss)//连四周正好可以防止高地把它围起来
73         {
74             temp=ji[now];
75             if(temp.x>1&&abs(h[temp.x-1][temp.y])<=temp.val)
76                 match(ha[temp.x][temp.y],ha[temp.x-1][temp.y]);
77             if(temp.x<n&&abs(h[temp.x+1][temp.y])<=temp.val)
78                 match(ha[temp.x][temp.y],ha[temp.x+1][temp.y]);
79             if(temp.y>1&&abs(h[temp.x][temp.y-1])<=temp.val)
80                 match(ha[temp.x][temp.y],ha[temp.x][temp.y-1]);
81             if(temp.y<m&&abs(h[temp.x][temp.y+1])<=temp.val)
82                 match(ha[temp.x][temp.y],ha[temp.x][temp.y+1]);
83             ++now;
84         }
85         temp=ji[i];
86         if(!flag[fin(ha[temp.x][temp.y])])
87         {
88             ++ans;
89             //printf("x=%d y=%d
",temp.x,temp.y);
90             flag[fin(ha[temp.x][temp.y])]=1;
91         }
92     }
93     
94     cout<<ans;
95     //while(1);
96     return 0;
97 }
code
原文地址:https://www.cnblogs.com/A-LEAF/p/7354044.html