[离散化][floodfill] Sculpture Uva12171,HDU2771

题目描述

无
Imagine a box, made of copper plate. Imagine a second one, intersecting the first one, and several others, intersecting each other (or not). That is how the sculptor Oto Boxing constructs his sculptures. In fact he does not construct that much, he only makes the design; the actual construction is contracted out to a construction company. For the calculation of the costs of construction the company needs to know the total area of copper plate involved. Parts of a box that are hidden in another box are not realized in copper, of course. (Copper is quite expensive, and prices are rising.) After construction, the total construction is plunged into a bath of chemicals. To prevent this bath from running over, the construction company wants to know the total volume of the construction. Given that a construction is a collection of boxes, you are asked to calculate the area and the volume of the construction.

Some of Oto’s designs are connected, others are not. Either way, we want to know the total area and the total volume. It might happen that the boxes completely enclose space that is not included in any of the boxes (see the second example below). Because the liquid cannot enter that space, its volume must be added to the total volume. Copper plate bordering this space is superfluous, of course, so it does not add to the area.

Input
On the first line one positive number: the number of testcases, at most 100. After that per testcase:

  • One line with an integer n (1 ≤ n ≤ 50): the number of boxes involved.
  • n lines with six positive integers x0, y0, z0, x, y, z (1 ≤ x0, y0, z0, x, y, z ≤ 500): the triple (x0, y0, z0) is the vertex of the box with the minimum values for the coordinates and the numbers x, y, z are the dimensions of the box (x, y and z dimension, respectively). All dimensions are in centimeters. The sides of the boxes are always parallel to the coordinate axes.

Output
Per testcase:

  • One line with two numbers separated by single spaces: the total amount of copper plate needed (in cm2), and the total volume (in cm3).

Sample Input
2
2
1 2 3 3 4 5
6 2 3 3 4 5
7
1 1 1 5 5 1
1 1 10 5 5 1
1 1 2 1 4 8
2 1 2 4 1 8
5 2 2 1 4 8
1 5 2 4 1 8
3 3 4 1 1 1

Sample Output
188 120
250 250

题解

解该题是遇到了很多坑。看到这题第一想法是用floodfill将所有长方体标记再统计体积和面积。然而,题目提示可能有互相嵌套的长方体。直接标记长方体的话不好处理。借鉴别人思路,可以将floodfill 的图扩大一层,让所有外部无长方体区域联通。然后直接标记“空气”,再统计体积和面积。
然而,直接用500*500*500 的空间进行floodfill会发现,用dfs会爆栈,用bfs依然耗时太多。于是便要用到一种离散化方法,(另一道离散题)。这里着重整理这种离散方法和floodfill。

floodfill

floodfill可用于图中连通块的统计。可以使用bfs或dfs实现。具体可看:Floodfill
在解该题时发现标记的位置对时间复杂度影响很大,如下:

void floodfill(int Lx, int Ly, int Lz){
    queue<int> qu;
    qu.push(0);
    G[0][0][0] = -1;
    while(!qu.empty()){
        int s = qu.front();qu.pop();
        int x = (s>>16)&0xff, y = (s>>8)&0xff, z = s&0xff;
        G[x][y][z] = -1;//若放在此处会进行许多无效循环
        for(int i = 0; i<6; i++){
            int fx = x+dx[i], fy = y+dy[i], fz = z+dz[i];
            if(!(fx<0||fx>=Lx||fy<0||fy>=Ly||fz<0||fz>=Lz)&&!G[fx][fy][fz]){
                //G[fx][fy][fz] = -1;
                qu.push((fx<<16)|(fy<<8)|(fz));
            }
        }
    }
}

离散化

最开始觉得离散化需要等比压缩之类的操作。后来明白离散时只需保留相对的位置关系,用另外的存储空间保留原始数据。该题离散时使用了以下方法:

int compress(int *X, int *vX, int n){
    memcpy(vX, X, sizeof(int)*n);//1
    vX[n] = -1;
    sort(vX, vX+n+1);
    int m = unique(vX, vX+n+1) - vX;//2
    for(int i = 0; i<n; i++)
    for(int k = 0; k<m; k++)
        if(X[i] == vX[k]) {X[i] = k;break;}//3
    return m;
}

可大致分成3个步骤:

  1. 保存原始位置信息
  2. 排序、去重,获得相对位置
  3. 将原始位置替换为相对位置

三步分别对应代码中注释1,2,3.
代码中用到了unique函数,这里简单总结一下:

unique函数

unique函数的的文件为:algorithm。其作用是除去数组或其他顺序结构中重复的元素。使用前要对数组进行排序。要注意的是去重后数组大小并未改变,且函数返回的值是去重后最后一个元素的地址。一般可用如下方法获得不重复元素的个数

int m = unique(a, a+n) - a;

AC代码

#include <cstring>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <iostream>
using namespace std;
const int maxn = 100+2;

int G[maxn][maxn][maxn];
int vx[maxn], vy[maxn], vz[maxn];
int x[maxn], y[maxn], z[maxn];

const int dx[6] = {1,0,0,-1,0,0};
const int dy[6] = {0,1,0,0,-1,0};
const int dz[6] = {0,0,1,0,0,-1};

int compress(int *X, int *vX, int n){
    memcpy(vX, X, sizeof(int)*n);
    vX[n] = -1;
    sort(vX, vX+n+1);
    int m = unique(vX, vX+n+1) - vX;
    for(int i = 0; i<n; i++)
    for(int k = 0; k<m; k++)
        if(X[i] == vX[k]) {X[i] = k;break;}
    return m;
}

void floodfill(int Lx, int Ly, int Lz){
    queue<int> qu;
    qu.push(0);
    G[0][0][0] = -1;
    while(!qu.empty()){
        int s = qu.front();qu.pop();
        int x = (s>>16)&0xff, y = (s>>8)&0xff, z = s&0xff;
        for(int i = 0; i<6; i++){
            int fx = x+dx[i], fy = y+dy[i], fz = z+dz[i];
            if(!(fx<0||fx>=Lx||fy<0||fy>=Ly||fz<0||fz>=Lz)&&!G[fx][fy][fz]){
                G[fx][fy][fz] = -1;
                qu.push((fx<<16)|(fy<<8)|(fz));
            }
        }
    }
}

int main(){
    //freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
    int N;
    cin>> N;
    while(N--){

        int n;
        scanf("%d", &n);
        for(int i = 0; i<n; i++){
            scanf("%d%d%d%d%d%d", x+i*2, y+i*2, z+i*2, x+i*2+1, y+i*2+1, z+i*2+1);
            x[i*2+1] += x[i*2]; y[i*2+1] += y[i*2]; z[i*2+1] += z[i*2];
        }

        int Lx = compress(x, vx, n*2);
        int Ly = compress(y, vy, n*2);
        int Lz = compress(z, vz, n*2);

        memset(G, 0, sizeof(G));
        for(int i = 0; i<n; i++)
        for(int xi = x[i*2]; xi<x[i*2+1]; xi++)
        for(int yi = y[i*2]; yi<y[i*2+1]; yi++)
        for(int zi = z[i*2]; zi<z[i*2+1]; zi++)
            G[xi][yi][zi] = true;

        floodfill(Lx, Ly, Lz);

        long long vol = 0, area = 0;
        for(int xi = 1; xi<Lx; xi++)
        for(int yi = 1; yi<Ly; yi++)
        for(int zi = 1; zi<Lz; zi++){
            int sx = vx[xi+1] - vx[xi], sy = vy[yi+1] - vy[yi], sz = vz[zi+1] - vz[zi];
            if(G[xi][yi][zi] != -1) vol += (long long)sx*sy*sz;
            for(int i = 0; i<6; i++){
                if(G[xi][yi][zi] == 1 && G[xi+dx[i]][yi+dy[i]][zi+dz[i]] == -1)
                    area += dx[i] ? sy*sz : dy[i] ? sx*sz : sx*sy;
            }
        }

        printf("%lld %lld\n", area, vol);
    }
}

猜你喜欢

转载自blog.csdn.net/loyxCCS/article/details/79680107