zoukankan      html  css  js  c++  java
  • ACM学习历程—Hihocoder 1291 Building in Sandbox(dfs && 离线 && 并查集)

    http://hihocoder.com/problemset/problem/1291

    前几天比较忙,这次来补一下微软笔试的最后一题,这题是这次微软笔试的第四题,过的人比较少,我当时在调试B题,没时间看这一题。不过打过之前一场BestCoder的应该都会有点思路,虽然BC那题是二维,这题是三维的,但是思路应该是一样的,没错,就是离线加并查集。

    正过来考虑的时候,发现第一个要求相邻块是好处理的,但是第二个要求能否到达(1000, 1000, 1000)这个条件似乎比较难判断,当时BC上的题根据题意是可以二分加搜索,但是这题的条件是不能二分的。

    离线并查集的话,比较好想(如果做过BC那题的话),就是先算上所有块,搜索一遍全图,把非块的用并查集联通起来。然后倒着来拆块,看要拆的块是否和边界(这里取了(0, 0, 1)这个边界非块)的非块联通(有公共的根),然后将拆掉块的地方和周围非块的地方联通。直到某一处的块与边界不联通,那么就是No。否则最后就是Yes。

    本地用dfs爆栈了,改bfs应该可以解决。不过直接交上去,评测机用dfs不会爆栈。。。

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <queue>
    #include <map>
    #include <set>
    #include <string>
    #include <vector>
    
    using namespace std;
    
    const int maxN = 100005;
    const int maxX = 103;
    int ufs[105*105*105];
    int n, x[maxN], y[maxN], z[maxN];
    int xx[] = {-1, 1,  0, 0,  0, 0};
    int yy[] = { 0, 0, -1, 1,  0, 0};
    int zz[] = { 0, 0,  0, 0, -1, 1};
    
    int findRoot(int x)
    {
        if (ufs[x] == x) return x;
        int fa = findRoot(ufs[x]);
        ufs[x] = fa;
        return fa;
    }
    
    void mergeUfs(int x, int y)
    {
        int fx, fy;
        fx = findRoot(x);
        fy = findRoot(y);
        ufs[fx] = fy;
    }
    
    bool inSameUfs(int x, int y)
    {
        int fx, fy;
        fx = findRoot(x);
        fy = findRoot(y);
        if (fx == fy) return true;
        else return false;
    }
    
    inline int Hash(int x, int y, int z)
    {
        return x*maxX*maxX+y*maxX+z;
    }
    
    void dfs(int x, int y, int z)
    {
        int t = Hash(x, y, z), tt;
        if (ufs[t] == -2 || ufs[t] != -1) return;
        if (ufs[t] == -1) ufs[t] = t;
        for (int i = 0; i < 6; ++i)
        {
            if (x+xx[i] < 0 || y+yy[i] < 0 || z+zz[i] <= 0) continue;
            if (x+xx[i] >= maxX || y+yy[i] >= maxX || z+zz[i] >= maxX) continue;
            tt = Hash(x+xx[i], y+yy[i], z+zz[i]);
            if (ufs[tt] != -1) continue;
            dfs(x+xx[i], y+yy[i], z+zz[i]);
            mergeUfs(t, tt);
        }
    }
    
    bool judge(int x, int y, int z)
    {
        bool flag = false;
        int t, tt, to;
        for (int i = 0; i < 6; ++i)
        {
            tt = Hash(x+xx[i], y+yy[i], z+zz[i]);
            if (ufs[tt] == -2) flag = true;
        }
        if (!flag) return false;
    
        flag = false;
        t = Hash(x, y, z);
        to = Hash(0, 0, 1);
        ufs[t] = t;
        for (int i = 0; i < 6; ++i)
        {
            tt = Hash(x+xx[i], y+yy[i], z+zz[i]);
            if (ufs[tt] == -2) continue;
            if (findRoot(to) == findRoot(tt)) flag = true;
            mergeUfs(t, tt);
        }
        return flag;
    }
    
    void input()
    {
        memset(ufs, -1, sizeof(ufs));
        int t;
        scanf("%d", &n);
        for (int i = 0; i < n; ++i)
        {
            scanf("%d%d%d", &x[i], &y[i], &z[i]);
            t = Hash(x[i], y[i], z[i]);
            ufs[t] = -2;
        }
        for (int i = 0; i < maxX; ++i)
            for (int j = 0; j < maxX; ++j)
            {
                t = Hash(i, j, 0);
                ufs[t] = -2;
            }
        for (int k = 1; k < maxX; ++k)
            for (int i = 0; i < maxX; ++i)
                for (int j = 0; j < maxX; ++j)
                    dfs(i, j, k);
    }
    
    void work()
    {
        for (int i = n-1; i >= 0; i--)
        {
            if (!judge(x[i], y[i], z[i]))
            {
                printf("No
    ");
                return;
            }
        }
        printf("Yes
    ");
    }
    
    int main()
    {
        //freopen("test.in", "r", stdin);
        //freopen("test.out", "w", stdout);
        int T;
        scanf("%d", &T);
        for (int times = 1; times <= T; ++times)
        {
            input();
            work();
        }
        return 0;
    }
    View Code
  • 相关阅读:
    第九章 引用
    第八章 指针
    第六章 面向对象
    第五章 if语句与运算符
    第四章 C++数据类型
    第三章 初步了解函数
    第二章 做一个简短的C++程序
    第一章 初始C++
    vs2012 快捷键+方法
    vue如何修改生效日期范围,以及转化成yyyy-mm-dd的格式
  • 原文地址:https://www.cnblogs.com/andyqsmart/p/5398963.html
Copyright © 2011-2022 走看看