hdu 5652 India and China Origins 并查集+BFS
题目链接: India and China Origins
题意:给定N*M的一个地图,1代表障碍物,0代表路,然后在Q个单位时间中,每过一个单位时间,向地图中某点添加一个障碍物,问到哪个时刻,人不能从第一行访问到最后一行。人只可以上下左右移动。如果到了Q时刻还从第一行能访问到最后一行,输出-1。
思路1:首先,把Q个点全部加到地图中,对点进行标号(1,N*M),然后BFS将所有能够联通的点合并到并查集中,然后从最后一个时刻开始,依次删除点,每删一个点,就把该点周围的点全部合并到并查集中。
思路2:二分+BFS,对时间Q进行 二分,然后判断从第一行BFS到最后一行是否联通。思路更加简单。
判断第一行与最后一行是否联通,并不需要对第一行和最后一行的每个点都遍历一次,可以在第一行之前增加一行,最后一行后面增加一行。在思路1 中我采用的是点标号为0表示中国,点标号为N*M + 1表示的是印度,然后合并的时候向这两个靠拢,最后联通的条件的,将par(a) ==0,par(b)==N * M + 1 进行合并。
给出并查集+BFS的代码:
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
using namespace std;
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#define FIN freopen("input.txt","r",stdin)
#define FOUT freopen("output.txt","w",stdout)
#define fst first
#define snd second
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
typedef __int64 LL;
//typedef long long LL;
typedef unsigned int uint;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
const int INF = 0x3f3f3f3f;
const double eps = 1e-6;
const int MAXN = 500 + 5;
const int MAXM = 500 + 5;
const int MAXQ = MAXN * MAXN;
const int DIR[][2] = {{ -1, 0}, {1, 0}, {0, -1}, {0, 1}};
struct Node {
int x, y;
Node() {}
Node(int x, int y) : x(x), y(y) {}
} cur;
int T, N, M, _Q, ans;
int X[MAXQ], Y[MAXQ];
char A[MAXN][MAXN];
queue<Node> Q;
bool vis[MAXN][MAXN];
int par[MAXN * MAXN];
inline int F(const int& x, const int& y) {
if (x == -1 && y == -1) return 0;
if (x == N && y == M) return F(N - 1, M - 1) + 1;
return x * M + y + 1;
}
int Find(const int& x) {
return x == par[x] ? x : (par[x] = Find(par[x]));
}
bool suc;
void Union(int a, int b) {
int pa = Find(a), pb = Find(b);
if (pa == pb) return;
if (pb == F(-1, -1)) swap(pa, pb);
if (pa == F(N, M)) swap(pa, pb);
if (pa == F(-1, -1) && pb == F(N, M)) {
suc = true;
par[pb] = pa;
}
else if (pa == F(-1, 1)) par[pb] = pa;
else if (pb == F(N, M)) par[pa] = pb;
else par[pb] = pa;
Find(a);
Find(b);
}
inline bool outRange(const int& x, const int& y) {
return x < 0 || y < 0 || x >= N || y >= M;
}
bool isOkay() {
return Find(F(-1, -1)) == Find(F(N, M)) || suc;
}
void update(const int& x, const int& y) {
int a = F(x, y), b;
for (int i = 0; i < 4; i++) {
int nx = x + DIR[i][0];
int ny = y + DIR[i][1];
if (outRange(nx, ny)) continue;
if (A[nx][ny] == '1') continue;
b = F(nx, ny);
Union(a, b);
}
}
void BFS(const int& srcX, const int& srcY) {
if (vis[srcX][srcY]) return;
vis[srcX][srcY] = true;
Q.push(Node(srcX, srcY));
while (!Q.empty()) {
cur = Q.front();
Q.pop();
int a = F(cur.x, cur.y), b;
for (int i = 0; i < 4; i++) {
int nx = cur.x + DIR[i][0];
int ny = cur.y + DIR[i][1];
if (outRange(nx, ny)) continue;
if (vis[nx][ny]) continue;
if (A[nx][ny] == '1') continue;
vis[nx][ny] = true;
b = F(nx, ny);
Union(a, b);
Q.push(Node(nx, ny));
}
}
}
int main() {
#ifndef ONLINE_JUDGE
FIN;
#endif // ONLINE_JUDGE
scanf("%d", &T);
while (T --) {
suc = false;
memset(vis, false, sizeof(vis));
scanf("%d %d", &N, &M);
for (int i = 0; i < N; i ++) {
scanf("%s", A[i]);
}
scanf("%d", &_Q);
int x, y;
for (int i = 0; i < _Q; i ++) {
scanf("%d %d", &X[i], &Y[i]);
A[X[i]][Y[i]] = '1';
}
for (int j = 0; j < M; j++) {
for (int i = 1; i < N - 1; i++) {
par[F(i, j)] = F(i, j);
}
par[F(0, j)] = A[0][j] == '0' ? F(-1, -1) : F(0, j);
par[F(N - 1, j)] = A[N - 1][j] == '0' ? F(N, M) : F(N - 1, j);
}
par[F(-1, -1)] = F(-1, -1);
par[F(N, M)] = F(N, M);
for (int i = 0; i < N; i ++) {
for (int j = 0; j < M; j ++) {
if (A[i][j] == '0' && !vis[i][j]) {
BFS(i, j);
}
}
}
if (isOkay()) {
puts("-1");
continue;
}
ans = 0;
for (int i = _Q - 1; i >= 0; i --) {
A[X[i]][Y[i]] = '0';
if (X[i] == 0) par[F(X[i], Y[i])] = F(-1, -1);
else if (X[i] == N - 1) par[F(X[i], Y[i])] = F(N, M);
update(X[i], Y[i]);
if (isOkay()) {
ans = i + 1;
break;
}
}
printf("%d\n", ans);
}
return 0;
}