1. 程式人生 > >【Luogu3457】POW-The Flood(並查集)

【Luogu3457】POW-The Flood(並查集)

logs truct inline stdin AI problem 每次 mark spa

【Luogu3457】POW-The Flood(並查集)

題面

洛谷

題解

我們知道,如果一個點和一個海拔不高於它的點相連
那麽連在那個點是更優的,所以考慮按照每個點的海拔排序
既然按照海拔排序,相鄰的海拔遞增的點可以放在同一個集合裏面討論
考慮使用並查集,每一個集合中只需要有一個抽水機即可

每次從海拔最低的點中選出一個點
將它和它周圍的海拔比當前海拔低的點直接鏈接在一起
同時,維護每個並查集是否存在抽水機
如果當前點是城市,並且所在的並查集中有抽水機了
顯然是不用再額外增加抽水機了
但是,如果當前點和周圍的點合並完之後,所在集合依然沒有抽水機
因為它所在的集合周圍的點海拔一定更高,不可能有抽水機

所以在當前集合中一點要放一個抽水機,
那麽,給當前集合放一個抽水機,同時答案加一即可

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register #define MAX 1010 inline int read() { RG int x=0,t=1;RG char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')t=-1,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return
x*t; } int n,m,g[MAX][MAX],bh[MAX][MAX]; struct Node{int id,x,y,w;}p[MAX*MAX]; bool operator<(Node a,Node b){return a.w<b.w;} int f[MAX*MAX],pl[MAX*MAX],tot,ans; int getf(int x){return x==f[x]?x:f[x]=getf(f[x]);} int d[4][2]={1,0,-1,0,0,1,0,-1}; void Merge(int u,int v) { pl[getf(v)]|=pl[getf(u)]; f[getf(u)]=getf(v); } int main() { freopen("pow.in","r",stdin); freopen("pow.out","w",stdout); n=read();m=read(); memset(g,-63,sizeof(g)); for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) g[i][j]=read(); for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) p[++tot]=(Node){bh[i][j]=tot,i,j,abs(g[i][j])}; for(int i=1;i<=tot;++i)f[i]=i; sort(&p[1],&p[tot+1]); for(int i=1;i<=tot;++i) { int X=p[i].x,Y=p[i].y; for(int k=0;k<4;++k) { int x=p[i].x+d[k][0],y=p[i].y+d[k][1]; if(abs(g[x][y])<=abs(g[X][Y]))Merge(getf(bh[x][y]),getf(bh[X][Y])); } if(abs(p[i+1].w)!=abs(p[i].w)) for(int j=i;abs(p[j].w)==abs(p[i].w);--j) if(g[p[j].x][p[j].y]>0) { int u=getf(bh[p[j].x][p[j].y]); if(!pl[u])pl[u]=1,++ans; } } printf("%d\n",ans); return 0; }

【Luogu3457】POW-The Flood(並查集)