[POI2007]POW-The Flood(并查集)
[POI2007]POW-The Flood
Description
AKD 市处在一个四面环山的谷地里。最近一场大暴雨引发了洪水,AKD 市全被水淹没了。Blue Mary,AKD 市的市长,召集了他的所有顾问(包括你)参加一
个紧急会议。经过细致的商议之后,会议决定,调集若干巨型抽水机,将它们放
在某些被水淹的区域,而后抽干洪水。
你手头有一张 AKD 市的地图。这张地图是边长为 mn 的矩形,被划分为 mn个 11 的小正方形。对于每个小正方形,地图上已经标注了它的海拔高度以及它是否是 AKD 市的一个组成部分。地图上的所有部分都被水淹没了。并且,由于这张地图描绘的地面周围都被高山所环绕,洪水不可能自动向外排出。显然,我们没有必要抽干那些非 AKD 市的区域。
每个巨型抽水机可以被放在任何一个 11 正方形上。这些巨型抽水机将持续地抽水直到这个正方形区域里的水被彻底抽干为止。当然,由连通器原理,所有能向这个格子溢水的格子要么被抽干,要么水位被降低。每个格子能够向相邻的格子溢水,“相邻的”是指(在同一高度水平面上的射影)有公共边。
Input
第一行是两个数 \(m,n(1<=m,n<=1000)\).
以下 m 行,每行 n 个数,其绝对值表示相应格子的海拔高度;若该数为正,表
示他是 AKD 市的一个区域;否则就不是。
请大家注意:所有格子的海拔高度其绝对值不超过 1000,且可以为零.
Output
只有一行,包含一个整数,表示至少需要放置的巨型抽水机数目。
Sample Input
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
Sample Output
2
考试的时候推样例都推了很久,有巨佬居然瞎xx乱搞拿了40???Orz
一个很重要的结论:我们要在所有“山谷”放抽水机。所以我们把每个点的海拔从小到大排序 ,对于每一个点,把它和周围比它低的点并入一个集合,因为比它低的点水排走了,它的水也就排走了,所以这个集合里最小的点放上了抽水机,就一定能保证这个集合的水全部被排走。
所以对于每一组海拔相同的点,如果它加入的集合中有城市但是没有放抽水机,就需要放抽水机。显然再往后海拔变高不可能在把它排空。
还有一个细节:将同一高度的格子合并完后再放置抽水机。显然两个格子3 4 3是可以在一个集合的,所以我们不要边合并边判断要不要放抽水机。
sb错误:排序后没有记录原位置,导致处理出错
#include<bits/stdc++.h>
using namespace std;
int read()
{
int x=0,w=1;char ch=getchar();
while(ch>'9'||ch<'0') {if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*w;
}
int m,n,cnt,last,ans;
bool fang[2000010];
int a[1010][1010],fa[2000010];
struct node{
int x,y,v,cnt;
}f[2000010];
bool cmp(node p,node q){return p.v<q.v;}
int gfa(int x){if(x==fa[x])return x;return fa[x]=gfa(fa[x]);}
void change(int k)
{
for(int i=last;i<=k;i++)
{
int ff=gfa(f[i].cnt);
if(!fang[ff]&&a[f[i].x][f[i].y]>0) ans++,fang[ff]=1;
}
}
void hebing(int x,int y)
{
int xx=gfa(x),yy=gfa(y);
if(xx==yy) return;
fa[yy]=xx;fang[xx]|=fang[yy];
}
int main()
{
n=read();m=read();memset(a,127,sizeof(a));
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
a[i][j]=read();
cnt++;f[cnt].x=i;f[cnt].y=j;f[cnt].v=abs(a[i][j]);fa[cnt]=cnt;f[cnt].cnt=cnt;
}
}
sort(f+1,f+1+cnt,cmp);last=1;f[0].v=0x7fffffff;
for(int i=1;i<=cnt;i++)
{
if(f[i].v!=f[i-1].v&&i!=1) {change(i-1);last=i;}
int x=f[i].x,y=f[i].y;
if(f[i].v>=abs(a[x-1][y])) hebing(f[i].cnt,(x-2)*m+y);
if(f[i].v>=abs(a[x+1][y])) hebing(f[i].cnt,x*m+y);
if(f[i].v>=abs(a[x][y-1])) hebing(f[i].cnt,(x-1)*m+y-1);
if(f[i].v>=abs(a[x][y+1])) hebing(f[i].cnt,(x-1)*m+y+1);
}change(f[cnt].cnt);
cout<<ans;
}