Building in Sandbox

本题来自hihocoder#1291

时间限制:30000ms

单点时限:3000ms

内存限制:256MB

描述

Little Hi is playing a sandbox voxel game. In the game the whole world is constructed by massive 1x1x1 cubes. The edges of cubes are parallel to the coordinate axes and the coordinates (x, y, z) of the center of each cube are integers.

At the beginning there is nothing but plane ground in the world. The ground consists of all the cubes of z=0. Little Hi needs to build everything by placing cubes one by one following the rules:

1. The newly placed cube must be adjacent to the ground or a previously placed cube. Two cubes are adjacent if and only if they share a same face.

2. The newly placed cube must be accessible from outside which means by moving in 6 directions(up, down, left, right, forward, backward) there is a path from a very far place - say (1000, 1000, 1000) in this problem - to this cube without passing through ground or other cubes.

Given a sequence of cubes Little Hi wants to know if he can build the world by placing the cubes in such order.

输入

The first line contains the number of test cases T(1 <= T <= 10).

For each test case the first line is N the number of cubes in the sequence.

The following N lines each contain three integers x, y and z indicating the coordinates of a cube.

For 20% of the data, 1 <= N <= 1000, 1 <= x, y, z <= 10.

For 100% of the data, 1 <= N <= 100000, 1 <= x, y, z <= 100.

输出

For each testcase output "Yes" or "No" indicating if Little Hi can place the cubes in such order.

样例提示

In the first test case three cubes are placed on the ground. It‘s OK.

In the second test case (1, 3, 2) is neither on the ground nor adjacent to previous cubes. So it can‘t be placed.

In the last test case (2, 2, 1) can not be reached from outside. So it can‘t be placed.

样例输入

3
3
1 1 1
1 2 1
1 3 1
3
1 1 1
1 2 1
1 3 2
17
1 1 1
1 2 1
1 3 1
2 3 1
3 3 1
3 2 1
3 1 1
2 1 1
2 1 2
1 1 2
1 2 2
1 3 2
2 3 2
3 3 2
3 2 2
2 2 2
2 2 1

样例输出

Yes
No
No

对于这道题,我们需要检测一个方块序列能不能被逐个放置,只需检查两个条件,第一个条件是检查新放入的方块是否与之前放入的方块相邻,这个很容易做到。关键在于第二个条件,我们需要检测新放入的方块能否通往无穷远处。一个基本的想法是使用floodfill,不过如果直接对每个方块使用这个方法的话,我们的算法会超时。一个想法是,我们希望能够动态地维护哪些地方可以通往无穷远处,但是问题在于,我们很难判断一个放入方块的操作是否会导致某一块区域被封闭起来。于是这道题的突破口正在此处,如果我们按顺序往里放方块的话,我们很难判断放入方块是否会封闭住一些区域,但是如果我们考虑一个逆向的过程,往外拿方块呢?每拿一个方块,我们就在拿掉的地方进行一次floodfill,这样我们就能算出拿掉这个方块后我们增加了哪些外部点。同时,我们只需要查看一个方块是否与外部点相邻,就能判断能否拿掉这个方块。容易验证,我们能顺序地放入方块,当且仅当满足相邻条件,且我们可以逆向的拿掉方块。

代码如下:

#include<iostream>
#include<vector>
#include<deque>
#include<stack>
#include<string>
#include<algorithm>
#include<string.h>
#include<sstream>

struct Point {
    int x, y, z;
    Point() : x(0), y(0), z(0) {};
    Point(int a, int b, int c) : x(a), y(b), z(c) {}
};

int MAX_C;
const int MAX_N = 100000+5;
const int dir[6][3] = {
    {1, 0, 0},
    {0, 1, 0},
    {0, 0, 1},
    {-1, 0, 0},
    {0, -1, 0},
    {0, 0, -1}
};

int pos[100 + 2][100 + 2][100 + 2];
int is_out[100 + 2][100 + 2][100 + 2];
Point cors[MAX_N];

using namespace std;

bool has_adj(int x, int y, int z) {
    if (z == 1) return true;

    for (int d = 0; d < 6; ++d) {
        int x1 = x + dir[d][0];
        int y1 = y + dir[d][1];
        int z1 = z + dir[d][2];

        if (pos[x1][y1][z1]) return true;
    }

    return false;
}

bool can_take(int x, int y, int z) {
    for (int d = 0; d < 6; ++d) {
        int x1 = x + dir[d][0];
        int y1 = y + dir[d][1];
        int z1 = z + dir[d][2];

        if (is_out[x1][y1][z1]) return true;
    }

    return false;
}

void my_bfs(int x, int y, int z) {
    deque<Point> q;
    Point p0(x, y, z);
    q.push_back(p0);

    while (!q.empty()) {
        Point p = q[0];
        q.pop_front();

        if (p.z < 1 || p.z > MAX_C + 1 || p.x < 0 || p.x > MAX_C + 1 || p.y < 0 || p.y > MAX_C + 1) continue;
        if (is_out[p.x][p.y][p.z] || pos[p.x][p.y][p.z]) continue;

        is_out[p.x][p.y][p.z] = 1;
        for (int d = 0; d < 6; ++d) {
            int x1 = p.x + dir[d][0];
            int y1 = p.y + dir[d][1];
            int z1 = p.z + dir[d][2];

            Point p1(x1, y1, z1);
            q.push_back(p1);
        }

    }

}

int main() {
    int T;
    cin >> T;
    for (int t = 0; t < T; ++t) {
        int N;
        cin >> N;
        memset(pos, 0, sizeof(pos));
        memset(is_out, 0, sizeof(is_out));

        bool is_possible = true;
        MAX_C = 0;
        for (int i = 0; i < N; ++i) {
            int x, y, z;
            cin >> x >> y >> z;
            cors[i].x = x;
            cors[i].y = y;
            cors[i].z = z;
            MAX_C = max(x, MAX_C);
            MAX_C = max(y, MAX_C);
            MAX_C = max(z, MAX_C);
            if (!pos[x][y][z] && has_adj(x, y, z)) {
                pos[x][y][z] = 1;
            }
            else {
                is_possible = false;
                //break;
            }
        }

        if (!is_possible) {
            cout << "No" << endl;
            continue;
        }

        else {
            my_bfs(0, 0, 1);

            for (int i = N - 1; i >= 0; --i) {
                int x = cors[i].x;
                int y = cors[i].y;
                int z = cors[i].z;
                if (!can_take(x, y, z)) {
                    is_possible = false;
                    break;
                }
                pos[x][y][z] = 0;
                my_bfs(x, y, z);
            }

            if (is_possible) cout << "Yes" << endl;
            else cout << "No" << endl;

        }
    }

    //system("pause");
    return 0;
}
时间: 2024-10-06 15:57:06

Building in Sandbox的相关文章

ACM学习历程—Hihocoder 1291 Building in Sandbox(dfs &amp;&amp; 离线 &amp;&amp; 并查集)

http://hihocoder.com/problemset/problem/1291 前几天比较忙,这次来补一下微软笔试的最后一题,这题是这次微软笔试的第四题,过的人比较少,我当时在调试B题,没时间看这一题.不过打过之前一场BestCoder的应该都会有点思路,虽然BC那题是二维,这题是三维的,但是思路应该是一样的,没错,就是离线加并查集. 正过来考虑的时候,发现第一个要求相邻块是好处理的,但是第二个要求能否到达(1000, 1000, 1000)这个条件似乎比较难判断,当时BC上的题根据题

Building good docker images

The docker registry is bursting at the seams. At the time of this writing, a search for "node" gets just under 1000 hits. How does one choose? What constitutes a good docker image? This is a subjective matter, but I have some criteria for a dock

(转载)解决AndroidStudio导入项目在 Building gradle project info 一直卡住

源地址http://blog.csdn.net/yyh352091626/article/details/51490976 Android Studio导入项目的时候,一直卡在Building gradle project info这一步,主要原因还是因为被墙的结果.gradle官网虽然可以访问,但是速度连蜗牛都赶不上... 解决办法主要有两种,一是直接下载gradle离线包,二是修改项目的gradle-wrapper.properties里的gradle版本为自己电脑已有的版本. 离线包下载导

ZOJ 3820 Building Fire Stations

Building Fire Stations Time Limit: 5000ms Memory Limit: 131072KB This problem will be judged on ZJU. Original ID: 382064-bit integer IO format: %lld      Java class name: Main Special Judge Marjar University is a beautiful and peaceful place. There a

hdu 5033 Building(斜率优化)

Building Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others) Total Submission(s): 1237    Accepted Submission(s): 350 Special Judge Problem Description Once upon a time Matt went to a small town. The town was so sma

ZOJ 1718 POJ 2031 Building a Space Station 修建空间站 最小生成树 Kruskal算法

题目链接:ZOJ 1718 POJ 2031 Building a Space Station 修建空间站 Building a Space Station Time Limit: 2 Seconds      Memory Limit: 65536 KB You are a member of the space station engineering team, and are assigned a task in the construction process of the statio

Building Block HDU - 2818 (并查集)

Building Block HDU - 2818 题意:搬砖...每一次可以把a所在的那一堆放到b所在的那一堆上面,问第x号砖下面有几块砖. 记录一下到根节点的距离(dw),以及根节点上方有几块砖(up). 1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int maxn=30010; 5 int f[maxn],up[maxn],dw[maxn]; 6 7 int gf(int x){ 8 if(x==f[x]){ 9

JVM building

http://hg.openjdk.java.net/jdk7/jdk7/raw-file/tip/README-builds.html#ant http://hg.openjdk.java.net/jdk8/jdk8/raw-file/tip/README-builds.html Building OpenJDK 9 on Ubuntu http://www.tuicool.com/articles/v2aaEv 图文解析在Linux下搭建Hotspot JVM源码调试环境 | How to

Building Maintainable Software-java篇之Keep Architecture Components Balanced

Building encapsulation boundaries is a crucial skill in software architecture. -George H. Fairbanks in Just Enough Architecture Guideline: ? Balance the number and relative size of top-level components in your code. ? Do this by organizing source cod