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\n");
            return;
        }
    }
    printf("Yes\n");
}

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

时间: 2024-10-13 20:57:23

ACM学习历程—Hihocoder 1291 Building in Sandbox(dfs && 离线 && 并查集)的相关文章

ACM学习历程—Hihocoder 1233 Boxes(bfs)(2015北京网赛)

hihoCoder挑战赛12 时间限制:1000ms 单点时限:1000ms 内存限制:256MB   描述 There is a strange storehouse in PKU. In this storehouse there are n slots for boxes, forming a line. In each slot you can pile up any amount of boxes. The limitation is that you can only pile a

ACM学习历程—Hihocoder 1164 随机斐波那契(数学递推)

时间限制:5000ms 单点时限:1000ms 内存限制:256MB 描述 大家对斐波那契数列想必都很熟悉: a0 = 1, a1 = 1, ai = ai-1 + ai-2,(i > 1). 现在考虑如下生成的斐波那契数列: a0 = 1, ai = aj + ak, i > 0, j, k从[0, i-1]的整数中随机选出(j和k独立). 现在给定n,要求求出E(an),即各种可能的a数列中an的期望值. 输入 一行一个整数n,表示第n项.(1<=n<=500) 输出 一行一个

ACM学习历程—Hihocoder 1289 403 Forbidden(字典树 || (离线 &amp;&amp; 排序 &amp;&amp; 染色))

http://hihocoder.com/problemset/problem/1289 这题是这次微软笔试的第二题,过的人比第三题少一点,这题一眼看过去就是字符串匹配问题,应该可以使用字典树解决.不过当时还有一个想法就是离线处理,把所有查询进行排序,然后用rule去匹配查询,进行染色处理,而且每个查询只进行一次染色.事实证明,如果比赛的时候采用第二种方法应该能拿全分,但是我用了第一种方法,导致只拿了10分...因为我没有考虑同一个rule出现两次的情况,但是字典树中会直接被后面的rule覆盖,

ACM学习历程—Hihocoder 1288 Font Size(暴力 || 二分)

http://hihocoder.com/problemset/problem/1288 这题是这次微软笔试的第一题,关键的是s的上限是min(w, h),这样s的范围只有到1000,这样就可以直接暴力了,当然用二分也行,不过暴力写起来更快一点. 代码: #include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #inc

ACM学习历程—Hihocoder 1290 Demo Day(动态规划)

http://hihocoder.com/problemset/problem/1290 这题是这次微软笔试的第三题,过的人比第一题少一点,这题一眼看过去就是动态规划,不过转移方程貌似不是很简单,调试了比较久才正确,不过好在是1A,但是最后只留了一个小时多一点给B题,也导致了B题最后也没能AC掉.首先状态是很好确定的p[i][j][k]表示走到第i行第j个格子时,方向是k的情况下的最小改变格子数目.(k from {0, 1})而且由于只有往下和往右走,所以中间过程进行转移时改变的格子不会影响后

ACM学习历程—Hihocoder 1139 二分&#183;二分答案(bfs)

http://hihocoder.com/problemset/problem/1139 这题提示上写的是二分,但是感觉不二分应该也可以,至少题目是AC的... 二分的思想就是二分答案的值,看能不能在k步内,得到这个答案值,可以采用bfs来判定. 不二分的话,就是需要一个dis[]数组来保存在前k步内,每个点的最小索敌值,因为bfs在往后的过程中step是越来越大的,所以前面能达到更小的,显然不会重复再跑大的,然后bfs的过程中更新即可.类似于spfa,但是没有对队列去重. 代码: #inclu

ACM学习历程—Hihocoder 1177 顺子(模拟 &amp;&amp; 排序 &amp;&amp; gcd)(hihoCoder挑战赛12)

时间限制:6000ms 单点时限:1000ms 内存限制:256MB   描述 你在赌场里玩梭哈,已经被发了4张牌,现在你想要知道发下一张牌后你得到顺子的概率是多少? 假定赌场使用的是一副牌,四种花色的A.2.3.....J.Q.K共52张,这副牌只发给你了4张,你的剩下一张牌从剩下48张中任意取出一张. 顺子指的是点数连续的五张牌,包括10.J.Q.K.A这种牌型(不包含同花顺,即构成顺子的五张牌花色不能相同).参见:https://zh.wikipedia.org/wiki/%E6%92%B

ACM学习历程—Hihocoder 1178 计数(位运算 &amp;&amp; set容器)(hihoCoder挑战赛12)

时间限制:10000ms 单点时限:1000ms 内存限制:256MB   描述 Rowdark是一个邪恶的魔法师.在他阅读大巫术师Lich的传记时,他发现一类黑魔法来召唤远古生物,鱼丸. 魔法n能召唤类型i鱼丸当且仅当i能够被表示为x xor n*x对于某个正整数x和固定的n. Rowdark想知道类型为[L,R]之间的鱼丸有多少种能被魔法n召唤. 输入 输入第一行包含个整数n(1 ≤ n ≤ 107). 第二行包含两个整数,L, R(0 ≤ L ≤ R ≤ 107). 输出 一行一个整数表示

ACM学习历程——hihoCoder挑战赛10A 01串(策略)

时间限制:7000ms 单点时限:1000ms 内存限制:256MB 描述 给定两个整数n和m,求是否存在恰好包含n个0和m个1的01串S,使得S中不存在子串"001"和"11". 如果存在符合条件的01串则输出字典序最小的S,否则输出NO. 输入 一行两个整数,表示n和m.(0<=n,m<=100000,0<n+m) 输出 一行一个字符串,为字典序最小的S或者NO. 样例输入 2 3 样例输出 10101 由于不能存在001和11,故只能1010