题意:上边是中国,下边是印度,黑点的部分不可以走,下面的矩阵1代表黑点不能走,然后给了Q,每一次将一个点变成黑点,即不能走,问最少多少次就可以完成
思路:如果有一条黑点连成的线,从走到右的说明我们达成了目的,那就好办了,每一个黑点可以与周围的8个黑点相连,这样我们在最左边建个汇点最右边建个源点,每次询问这两个点在不在一个集合就行了,用并查集轻松实现,只要两个点相连就放到一个集合里
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <iostream> #include <algorithm> using namespace std; typedef long long ll; const int inf=0x3f3f3f3f; const int maxn=500010; int f[maxn]; int dir[8][2]={{1,0},{-1,0},{0,1},{0,-1},{-1,-1},{-1,1},{1,-1},{1,1}}; char str[510][510]; void init(){ for(int i=0;i<maxn;i++){ f[i]=i; } } int find1(int x){ if(x!=f[x]) f[x]=find1(f[x]); return f[x]; } void unite(int a,int b){ int aa=find1(a); int bb=find1(b); if(aa==bb) return ; f[aa]=bb; } int main(){ int T,n,m,ask,a,b; scanf("%d",&T); while(T--){ init(); scanf("%d%d",&n,&m); int S=0,T=n*m+1; for(int i=1;i<=n;i++) scanf("%s",str[i]+1); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ if(j==1&&str[i][j]=='1') unite(S,(i-1)*m+j); if(j==m&&str[i][j]=='1') unite(T,(i-1)*m+j); if(str[i][j]=='1'){ for(int k=0;k<8;k++){ int xx=i+dir[k][0]; int yy=j+dir[k][1]; if(xx<1||xx>n||yy<1||yy>m||str[xx][yy]!='1') continue; unite((xx-1)*m+yy,(i-1)*m+j); } } } } int ans=-1; if(find1(S)==find1(T)) ans=0; scanf("%d",&ask); for(int j=1;j<=ask;j++){ scanf("%d%d",&a,&b); a++;b++; if(ans!=-1) continue; str[a][b]='1'; if(b==1) unite(S,(a-1)*m+b); if(b==m) unite(T,(a-1)*m+b); for(int i=0;i<8;i++){ int xx=a+dir[i][0]; int yy=b+dir[i][1]; if(xx<1||xx>n||yy<1||yy>m||str[xx][yy]!='1') continue; unite((xx-1)*m+yy,(a-1)*m+b); } if(find1(S)==find1(T)) ans=j; } printf("%d\n",ans); } return 0; }
时间: 2024-11-03 22:03:06