题目大意:有个由n个(n<=50)长方体组成的雕塑,现在给出这n个长方体的“左下角”坐标(x,y,z都最小)和x,y,z,方向上的长度,要求算出雕塑的表面积(从外面看的到的,里面的不算),体积(内部的空心也算雕塑的体积)。
思路:先离散化,之后怎么求表面积呢?若是对长方体做floodfill会把雕塑的内表面积也算进去,可以考虑对空气做floodfill。具体是先扩展区域,用离散化把整个区域分成多个有限区域,每个区域中的状态(是雕塑还是空气)是一致的,且每个区域都是长方体,然后对空气floodfill把他们的体积累加起来,如果碰到雕塑则把他们的接触面积累加起来。最后,累加的接触面就是雕塑的外表面,整个区域的体积减去累加起来的空气体积就是雕塑的体积。
代码基本上是照着网上的打下来的:
参考代码
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<vector>
#include<map>
#include<stack>
#include<string>
using namespace std;
struct Point{
int x,y,z;
};
struct rec{
int x1,y1,z1,x2,y2,z2;//分别表示长方体的x,y,z方向的两个边界的坐标
}p[110];
int x[110],y[110],z[110];//离散化,分别表示所有的长方体的边界x,y,z升序序列。
int vis[110][110][110]; //表示是否访问过
int loc[110][110][110]; //表示这块区域是否有长方体
int numx,numy,numz;//分别表示离散化的x,y,z点的个数
int ans1=0,ans2=0;//分别表示表面积和体积
//相邻情况
const int u[6]={0,0,0,0,1,-1};
const int v[6]={1,-1,0,0,0,0};
const int w[6]={0,0,1,-1,0,0};
int solve(int flag,Point now){
switch (flag){
case 0: return (x[now.x+1]-x[now.x])*(z[now.z+1]-z[now.z]);
case 1: return (x[now.x+1]-x[now.x])*(z[now.z+1]-z[now.z]);
case 2: return (x[now.x+1]-x[now.x])*(y[now.y+1]-y[now.y]);
case 3: return (x[now.x+1]-x[now.x])*(y[now.y+1]-y[now.y]);
case 4: return (y[now.y+1]-y[now.y])*(z[now.z+1]-z[now.z]);
case 5: return (y[now.y+1]-y[now.y])*(z[now.z+1]-z[now.z]);
}
return 0;
}
int solve1(int flag,int nowx,int nowy,int nowz){//计算表面积
if (flag==0) return (x[nowx+1]-x[nowx])*(z[nowz+1]-z[nowz]);
if (flag==1) return (x[nowx+1]-x[nowx])*(z[nowz+1]-z[nowz]);
if (flag==2) return (x[nowx+1]-x[nowx])*(y[nowy+1]-y[nowy]);
if (flag==3) return (x[nowx+1]-x[nowx])*(y[nowy+1]-y[nowy]);
if (flag==4) return (z[nowz+1]-z[nowz])*(y[nowy+1]-y[nowy]);
if (flag==5) return (z[nowz+1]-z[nowz])*(y[nowy+1]-y[nowy]);
return -1;
}
int IDX(int aim){//求aim最低可以插入到x【】中的哪个位置
return lower_bound(x,x+numx,aim)-x;
}
int IDY(int aim){
return lower_bound(y,y+numy,aim)-y;
}
int IDZ(int aim){
return lower_bound(z,z+numz,aim)-z;
}
void bfs(){
queue<Point> q;
while (!q.empty()) q.pop();//强迫症,清肠
q.push((Point){0,0,0});//从 这点开始
ans2=(x[1]-x[0])*(y[1]-y[0])*(z[1]-z[0]);
vis[0][0][0]=1;
while(!q.empty()){
Point now2=q.front();
q.pop();
for(int i=0;i<6;i++){
int tx=now2.x+u[i];
int ty=now2.y+v[i];
int tz=now2.z+w[i];
if (tx<0||tx>=numx-1||ty<0||ty>=numy-1||tz<0||tz>=numz-1||vis[tx][ty][tz])
continue;
if (loc[tx][ty][tz]){//是墙(长方体)
ans1+=solve(i,now2); //加上表面积
}else {//是空气
ans2+=(x[tx+1]-x[tx])*(y[ty+1]-y[ty])*(z[tz+1]-z[tz]);//加上空气面积
vis[tx][ty][tz]=1;
q.push((Point){tx,ty,tz});
}
}
}
}
int main (){
int n;
scanf ("%d",&n);
for (int i=0;i<n;i++){
scanf ("%d %d %d %d %d %d",&p[i].x1,&p[i].y1,&p[i].z1,&p[i].x2,&p[i].y2,&p[i].z2);
p[i].x2+=p[i].x1;
p[i].y2+=p[i].y1;
p[i].z2+=p[i].z1;
//把离散化的坐标存入,x[1]~x[2*n],y[1]~....
x[2*i+1]=p[i].x1;
x[2*i+2]=p[i].x2;
y[2*i+1]=p[i].y1;
y[2*i+2]=p[i].y2;
z[2*i+1]=p[i].z1;
z[2*i+2]=p[i].z2;
}
x[0]=0;y[0]=0;z[0]=0;
x[2*n+1]=1001;y[2*n+1]=1001;z[2*n+1]=1001;
sort(x,x+2*n+2);
sort(y,y+2*n+2);
sort(z,z+2*n+2);
numx=unique(x,x+2*n+2)-x;
numy=unique(y,y+2*n+2)-y;
numz=unique(z,z+2*n+2)-z;
//经过以上处理之后离散化就完成了,这些离散点把整个区域(扩展出的区域)分成(numx-1)(numy-1)(numz-1)块
memset(loc,0,sizeof(loc));
memset(vis,0,sizeof(vis));
//然后要统计记录这些离散化的区域是空气还是长方体
for (int now=0;now<n;now++){//最外层遍历的是长方体
for (int i=IDX(p[now].x1);i<IDX(p[now].x2);i++)
for (int j=IDY(p[now].y1);j<IDY(p[now].y2);j++)
for (int k=IDZ(p[now].z1);k<IDZ(p[now].z2);k++)
loc[i][j][k]=1;//代表x向第i到i+1离散点 ,y向第j到j+1离散点,z向第k到k+1离散点 表示的那块区域是长方体
}
bfs();
printf ("%d %d",ans1,x[numx-1]*y[numy-1]*z[numz-1]-ans2);
return 0;
}