并查集 hdu5652 India and China Origins

传送门:点击打开链接

题意:告诉你地图的大小,每年有的地方会长出山峰,问什么时候两端开始不连通的。

思路:先到最后一年,就是长出很多山峰时开始。

之后相当于把山峰拆掉,所以就是把4个方向的空地用并查集合并,然后判断两端是否已经连通。

就这样倒着xjb搞,就能出答案了,注意点细节和输出答案的时间就行了

#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <stack>
#include <queue>
#include <cstdio>
#include <cctype>
#include <string>
#include <vector>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
#include <functional>
#define fuck(x) cout<<"["<<x<<"]"
#define FIN freopen("input.txt","r",stdin)
#define FOUT freopen("output.txt","w+",stdout)
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;

const int MX = 4e5 + 5;
const int mod = 1e9 + 7;

int P[MX];
int find(int x) {
    return P[x] == x ? x : (P[x] = find(P[x]));
}

int n, m, Q;
char S[505][505];
int WX[MX], WY[MX];
int dist[][2] = {{0, 1}, {0, -1}, {1, 0}, { -1, 0}};

inline int id(int x, int y) {
    return (x - 1) * m + y;
}
inline void Union(int u, int v) {
    u = find(u); v = find(v);
    if(u != v) P[v] = u;
}

int main() {
    //FIN;
    int T; scanf("%d", &T);
    while(T--) {
        scanf("%d%d", &n, &m);
        int Begin = m * n + 1, End = m * n + 2, tot = m * n + 2;
        for(int i = 1; i <= tot; i++) {
            P[i] = i;
        }
        for(int i = 1; i <= n; i++) {
            scanf("%s", S[i] + 1);
        }
        scanf("%d", &Q);
        for(int i = 1; i <= Q; i++) {
            scanf("%d%d", &WX[i], &WY[i]);
            WX[i]++; WY[i]++;
            S[WX[i]][WY[i]] = '1';
        }

        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= m; j++) {
                if(S[i][j] == '0') {
                    for(int k = 0; k < 4; k++) {
                        int nx = i + dist[k][0], ny = j + dist[k][1];
                        if(ny < 1 || ny > m || S[nx][ny] == '1') continue;
                        if(nx == 0) Union(id(i, j), Begin);
                        else if(nx == n + 1) Union(id(i, j), End);
                        else Union(id(i, j), id(nx, ny));
                    }
                }
            }
        }

        int ans = 0;
        if(find(Begin) == find(End)) {
            printf("-1\n");
            continue;
        }
        for(int i = Q; i >= 1; i--) {
            S[WX[i]][WY[i]] = '0';
            for(int k = 0; k < 4; k++) {
                int nx = WX[i] + dist[k][0], ny = WY[i] + dist[k][1];
                if(ny < 1 || ny > m || S[nx][ny] == '1') continue;
                if(nx == 0) Union(id(WX[i], WY[i]), Begin);
                else if(nx == n + 1) Union(id(WX[i], WY[i]), End);
                else Union(id(WX[i], WY[i]), id(nx, ny));
            }

            if(find(Begin) == find(End)) {
                ans = i; break;
            }
        }

        printf("%d\n", ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值