您的位置:首页 > 其它

BZOJ 1104: [POI2007]洪水pow 并查集

2016-11-03 16:17 351 查看
时空隧道

分析:

首先我们可以得出水泵一定是安在城市上的…

以上纯属瞎扯淡…只是答案相等可以…至于为什么我们待会儿再说…

我们取出所有的城市放在s集合中,因为海拔高的可以被海拔低的覆盖,所以我们从小到大排序从所有的元素中取出海拔小于等于当前城市海拔的元素,合并相邻元素,然后查询当前城市所在的联通块是否已经被覆盖,如果没有就在当前城市安上水泵…

回到最初的那句话…有一个数据是长这个样子的:



然后8是非城市点,其他都是城市点,显然水泵应该安在8,按照我们的代码我们会把水泵安在9,但是这样安放其实本质上是把水泵安在了8,我们维护了城市所在的集合,这个集合中的元素都比城市低,所以无论安在哪一处都会使得城市被抽干,所以其实是安在了这个集合中的点而不是城市这个点…

代码如下:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
//by NeighThorn
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=1000+5;
int n,m,h[maxn][maxn],fa[maxn*maxn],cnt,ans,mv[4][2]={1,0,-1,0,0,1,0,-1},have[maxn*maxn];
struct M{
int x,y,hei;
friend bool operator < (M a,M b){
return a.hei<b.hei;
}
}s[maxn*maxn],l[maxn*maxn];
inline int find(int x){
return fa[x]==x?x:fa[x]=find(fa[x]);
}
signed main(void){
scanf("%d%d",&n,&m);
cnt=0;memset(have,0,sizeof(have));
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
scanf("%d",&h[i][j]);
if(h[i][j]>0)
s[++cnt].x=i,s[cnt].y=j,s[cnt].hei=h[i][j];
else
h[i][j]=-h[i][j];
l[(i-1)*m+j].x=i,l[(i-1)*m+j].y=j,l[(i-1)*m+j].hei=h[i][j];
}
for(int i=1;i<=n*m;i++)
fa[i]=i;
for(int i=0;i<=n+1;i++)
h[i][0]=h[i][m+1]=inf;
for(int i=0;i<=m+1;i++)
h[0][i]=h[n+1][i]=inf;
sort(l+1,l+m*n+1);
sort(s+1,s+cnt+1);ans=0;
for(int i=1,k=1;i<=cnt;i++){
for(;k<=m*n&&l[k].hei<=s[i].hei;k++){
int x=l[k].x,y=l[k].y;
for(int j=0;j<=3;j++){
int xx=x+mv[j][0],yy=y+mv[j][1];
if(h[xx][yy]<=h[x][y])
have[find((x-1)*m+y)]|=have[find((xx-1)*m+yy)],fa[find((xx-1)*m+yy)]=find((x-1)*m+y);
}
}
if(!have[find((s[i].x-1)*m+s[i].y)])
ans++,have[find((s[i].x-1)*m+s[i].y)]=1;
}
cout<<ans<<endl;
return 0;
}


by >_< NeighThorn
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: