题意:上边是中国,下边是印度,黑点的部分不可以走,下面的矩阵1代表黑点不能走,然后给了Q,每一次将一个点变成黑点,即不能走,问最少多少次就可以完成
分析:这是一个连通性的问题。你会发现如果将所有操作逆序来看的话就很容易用并查集来处理了。 首先把所有的山峰都加到图中,然后逆序处理每个操作:
对某次操作,在图中删除该位置的山峰,然后判断两个点是否联通,一旦联通就得到了结果。 这里需要对China和India分别新建一个对应的节点。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <vector>
#include <set>
#include <list>
#include <queue>
#include <map>
#include <stack>
using namespace std;
#define L(i) i<<1
#define R(i) i<<1|1
#define INF 0x3f3f3f3f
#define pi acos(-1.0)
#define eps 1e-3
#define maxn 200010
#define MOD 100000000
int n,m,vis[550][550],fa[250010];
char s[550][550];
int mx[4] = {0,0,1,-1};
int my[4] = {1,-1,0,0};
pair<int,int> p[250010];
int Find(int x)
{
return fa[x] = fa[x] == x? fa[x] : Find(fa[x]);
}
void Union(int x,int y)
{
int fx = Find(x);
int fy = Find(y);
if(fx != fy)
fa[fy] = fx;
}
void slove(int x,int y)
{
vis[x][y] = 1;
for(int i = 0; i < 4; i++)
{
int dx = x + mx[i];
int dy = y + my[i];
if(dx < 0 || dx >= n || dy < 0 || dy >= m)
continue;
if(vis[dx][dy] || s[dx][dy] == '1')
continue;
vis[dx][dy] = 1;
Union(x*m+y,dx*m+dy);
slove(dx,dy);
}
}
int main()
{
int t,C = 1;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(int i = 0; i < n; i++)
scanf("%s",s[i]);
int k,u,v;
scanf("%d",&k);
for(int i = 0; i < k; i++)
{
scanf("%d%d",&u,&v);
s[u][v] = '1';
p[i].first = u;
p[i].second = v;
}
for(int i = 0; i < n*m+5; i++)
fa[i] = i;
memset(vis,0,sizeof(vis));
for(int i = 0; i < n; i++)
for(int j = 0; j < m; j++)
if(s[i][j] == '0' && !vis[i][j])
slove(i,j);
int k1 = n*m+1,k2 = n*m+2; //中国 印度看成两点</strong></span></span>
for(int i = 0; i < m; i++)
{
if(s[0][i] == '0')
Union(i,k1);
if(s[n-1][i] == '0')
Union(i+n*m-m,k2);
}
if(Find(k1) == Find(k2))
{
printf("-1\n");
continue;
}
int ans = k;
for(int i = k-1; i >= 0; i--)
{
u = p[i].first;
v = p[i].second;
s[u][v] = '0';
if(u == 0)
Union(v,k1);
if(u == n-1)
Union(v+n*m-m,k2);
for(int i = 0; i < 4; i++)
{
int du = u + mx[i];
int dv = v + my[i];
if(du < 0 || du >= n || dv < 0 || dv >= m)
continue;
if(s[du][dv] == '0')
Union(du*m+dv,u*m+v);
}
if(Find(k1) == Find(k2))
break;
ans = i;
}
printf("%d\n",ans);
}
return 0;
}