hdu 5652 India and China Origins 并查集+BFS

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;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值