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("\n"); 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("\n"); 46 } 47 printf("\n"); 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\n",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 }