题目:http://acm.hdu.edu.cn/showproblem.php?pid=5652
题意:
给出一个n*m的图,1是山峰,0是平原,还有q个操作,可以把0变成1,问最少前几次操作可以使得图的上端和下端完全阻隔,就是被1隔开。
分析:
判断是否完全隔开,就是判断是否1可以从左到右全都连起来,那么可以增加两个点s和e,表示最左端个最右端,如果是1,那么将1的八方是1的点连接起来,然后判断s和e是否连通。这个用并查集比较好做。还看到以一种思路是二分操作+bfs判联通。
并查集:
#include<cstdio>
#include<cstring>
using namespace std;
const int N=505;
int dx[]={-1,-1,-1,0,0,1,1,1};
int dy[]={-1,0,1,-1,1,-1,0,1};
int fa[N*N];
char g[N][N];
int findfa(int x){return x==fa[x]?x:fa[x]=findfa(fa[x]);}
void unionfa(int x,int y)
{
int xx=findfa(x),yy=findfa(y);fa[xx]=yy;
}
int main()
{
int T;scanf("%d",&T);
while(T--){
int n,m;
scanf("%d%d",&n,&m);
int s=n*m,e=s+1;
for(int i=0;i<=e;i++)fa[i]=i;
for(int i=0;i<n;i++)scanf("%s",g[i]);
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(g[i][j]=='0')continue;
if(j==0)unionfa(s,i*m+j);
if(j==m-1)unionfa(e,i*m+j);
for(int k=0;k<8;k++){
int x=dx[k]+i,y=dy[k]+j;
if(x<0||y<0||x>=n||y>=m||g[x][y]=='0')continue;
unionfa(x*m+y,i*m+j);
}
}
}
// if(findfa(s)==findfa(e)){printf("AAAAAAAAAAAAAA
");}
int q;scanf("%d",&q);
int ans=-1;
for(int i=0;i<q;i++){
int a,b; scanf("%d%d",&a,&b);g[a][b]='1';
if(ans!=-1)continue;
if(findfa(s)==findfa(e))ans=i;
if(b==0)unionfa(s,a*m+b);
if(b==m-1)unionfa(e,a*m+b);
for(int k=0;k<8;k++){
int x=dx[k]+a,y=dy[k]+b;
if(x<0||y<0||x>=n||y>=m||g[x][y]=='0')continue;
unionfa(x*m+y,a*m+b);
}
}
if(ans==-1&&findfa(s)==findfa(e))ans=q;
printf("%d
",ans);
}
return 0;
}