Problem UVA12171-Sculpture
Accept: 196 Submit: 1152
Time Limit: 3000 mSec
Problem Description
Imagine a box, made of copper plate. Imagine a second one, intersecting the rst 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 rst 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倒不是重点,困难的地方在于离散化(起码对我来说很困难),原来也做过两道离散化的题,但是对于这个东西没啥概念,这道题让我对离散化的理解深刻了一些。
离散化之后这里的长方体就变成了正方体,想到这一点对于理解整个思路很有帮助。
这里面还有一个思想就是用点代表长方体,此处用的是三个坐标均为最小的点来代表一个长方体。
lrj的代码中把函数封装在结构体感觉灰常方便,学习了。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <algorithm>
using namespace std; const int maxn = +;
const int maxl = +; int xl[maxn],yl[maxn],zl[maxn];
int xr[maxn],yr[maxn],zr[maxn]; int gra[maxn<<][maxn<<][maxn<<];
int xx[maxn<<],yy[maxn<<],zz[maxn<<];
int xcnt,ycnt,zcnt; int dx[] = {,-,,,,};
int dy[] = {,,,-,,};
int dz[] = {,,,,,-}; struct Point{
int x,y,z;
Point(int x = ,int y = ,int z = ) :
x(x),y(y),z(z) {}
bool valid()const{
if(<=x && <=y && <=z && x<xcnt- && y<ycnt- && z<zcnt-) return true;
else return false;
}
bool solid()const{
return gra[x][y][z] == ;
}
void Setvis()const{
gra[x][y][z] = ;
}
bool Getvis()const{
return gra[x][y][z] ==;
}
Point neighbour(int i)const{
return Point(x+dx[i],y+dy[i],z+dz[i]);
}
int volume()const{
return (xx[x+]-xx[x])*(yy[y+]-yy[y])*(zz[z+]-zz[z]);
}
int area(int dir)const{
if(dx[dir] != ) return (yy[y+]-yy[y])*(zz[z+]-zz[z]);
else if(dy[dir] != ) return (xx[x+]-xx[x])*(zz[z+]-zz[z]);
else return (xx[x+]-xx[x])*(yy[y+]-yy[y]);
}
}; int ID_find(int *num,int len,int tar){
return lower_bound(num,num+len,tar)-num;
} void floodfill(int &V,int &S){
Point c;
c.Setvis();
queue<Point> que;
que.push(c);
while(!que.empty()){
Point first = que.front();
que.pop();
V += first.volume();
for(int i = ;i < ;i++){
Point Next = first.neighbour(i);
if(Next.valid()){
if(Next.solid()){
S += first.area(i);
}
else if(!Next.Getvis()){
Next.Setvis();
que.push(Next);
}
}
}
}
V = maxl*maxl*maxl-V;
} void Unique(int *num,int cnt,int &ccnt){
sort(num,num+cnt);
ccnt = unique(num,num+cnt)-num;
} int main()
{
//freopen("input.txt","r",stdin);
int iCase;
scanf("%d",&iCase);
while(iCase--){
int n;
scanf("%d",&n);
int cnt = ;
xx[] = yy[] = zz[] = ;
xx[] = yy[] = zz[] = maxl;
for(int i = ;i < n;i++){
scanf("%d%d%d%d%d%d",&xl[i],&yl[i],&zl[i],&xr[i],&yr[i],&zr[i]);
xr[i] += xl[i],yr[i] += yl[i],zr[i] += zl[i];
xx[cnt] = xl[i],yy[cnt] = yl[i],zz[cnt++] = zl[i];
xx[cnt] = xr[i],yy[cnt] = yr[i],zz[cnt++] = zr[i];
}
Unique(xx,cnt,xcnt);
Unique(yy,cnt,ycnt);
Unique(zz,cnt,zcnt);
memset(gra,,sizeof(gra));
for(int i = ;i < n;i++){
int X1 = ID_find(xx,xcnt,xl[i]),X2 = ID_find(xx,xcnt,xr[i]);
int Y1 = ID_find(yy,ycnt,yl[i]),Y2 = ID_find(yy,ycnt,yr[i]);
int Z1 = ID_find(zz,zcnt,zl[i]),Z2 = ID_find(zz,zcnt,zr[i]);
for(int X = X1;X < X2;X++){ //这里一定是 < ,因为是以点代体,如果点到了边界,体就出去了
for(int Y = Y1;Y < Y2;Y++){
for(int Z = Z1;Z < Z2;Z++){
gra[X][Y][Z] = ;
}
}
}
}
int V = ,S = ;
floodfill(V,S);
printf("%d %d\n",S,V);
}
return ;
}