您的位置:首页 > 其它

UVa12171 Sculpture 离散化+搜索

2017-09-23 08:40 429 查看
题意:最多给定50个边平行于坐标轴的长方体组成一个雕塑,输入第一个为测试样例的数量,对于每组测试样例第一行是长方体的数量,接下来跟着输入长方体的坐标x0,y0,z0,x1,y1,z1(x0,y0,z0表示长方体顶点在三个方向的最小坐标,x1,y1,z1表示长方体在三个方向的长度)。长方体组成的雕塑内部可能有密闭的空心部分,这部分的体积要记入雕塑的总体积,而这部分的表面积无需计算进雕塑的表面积。

思路:参考紫书的思路,以边界长度作为这个空间的边长,即把1001*1001*1001(x0,x1范围是1~500所以每个方向最长是1000)的立方体作为包含雕塑的空间,空间的其余部分作为空气,对空气进行floodfill算法即搜索算法。然后考虑到对原始坐标500*500*500的遍历太耗时,对其进行离散化(把每个长方体的最为一个网格)则每个方向最多2*50个网格,100*100*100就可以满足要求,这个离散化数组组要用于搜索算法,计算体积和表面积时要用原始坐标数据。

下面是代码(带有自己理解算法时候的注释):

#include<stdio.h>
#include<string.h>
#include<queue>
#include<algorithm>
using namespace std;
const int maxn=55;
const int maxc=1001;
//用来存储原始坐标数据
int x0[maxn],y0[maxn],z0[maxn],x1[maxn],y1[maxn],z1[maxn];
//存储离散坐标个数和数据
int nx,ny,nz;
int xs[maxn*2],ys[maxn*2],zs[maxn*2];
//color是用于辨别三维网格是否为实心,在floodfill时也用于标记是否访问过
int color[maxn*2][maxn*2][maxn*2];
//用于当前网格的六个方向的移动
int dx[]={1,-1,0,0,0,0};
int dy[]={0,0,1,-1,0,0};
int dz[]={0,0,0,0,1,-1};
/*创建网格数据结构
*x,y,z个网格在离散坐标数组中的位置而不是原始坐标
*/
struct Cell{
int x, y, z;
Cell(int x=0,int y=0,int z=0):x(x),y(y),z(z){}
//判断网格是否越界
bool inside(){
return x>=0&&x<nx-1&&y>=0&&y<ny-1&&z>=0&&z<nz-1;
}
//判断是否为实心,即是否为雕塑的组成部分
bool solid(){
return color[x][y][z]==1;
}
//是否访问过
bool visited(){
return color[x][y][z]==2;
}
//标记为访问过
void setVis(){
color[x][y][z]=2;
}
//向相邻的网格移动,dir代表移动方向
Cell near(int dir){
return Cell(x+dx[dir], y+dy[dir], z+dz[dir]);
}
//计算该网格的原始体积并返回
int volume(){
return (xs[x+1]-xs[x])*(ys[y+1]-ys[y])*(zs[z+1]-zs[z]);
}
//计算该网格的表面积并返回
int area(int dir){
if(dx[dir]) return (ys[y+1]-ys[y])*(zs[z+1]-zs[z]); //如果dx[dir]不为零说明是从x方向移过来的,而我们是从空气中移动的,所以该X方向的面在表面
else if(dy[dir]) retu
4000
rn (xs[x+1]-xs[x])*(zs[z+1]-zs[z]); //同上
return (xs[x+1]-xs[x])*(ys[y+1]-ys[y]); //同上
}
};
//离散函数
void discretize(int* x, int& n) {
sort(x, x+n);
n = unique(x, x+n) - x;
}
//寻找x0在离散坐标数组中的位置
int pos(int* x, int n, int x0) {
return lower_bound(x, x + n, x0) - x;
}
//搜索对空气网格进行
void floodfill(int &v, int &s){
v = s = 0;
Cell c;
queue<Cell> q;
c.setVis();
q.push(c);
while(!q.empty()){
Cell c1=q.front(); q.pop();
v+=c1.volume();
for(int i=0;i<6;++i){
Cell c2=c1.near(i);
if(!c2.inside()) continue;
if(c2.solid()) s+=c1.area(i); //如果这个方向的是实心网格则记入表面积
else if(!c2.visited()){ //如果不是则空气,加入队列进行搜索
c2.setVis();
q.push(c2);
}
}
}
v = maxc*maxc*maxc - v;
}
int main(){
// freopen("input.txt", "r", stdin);
int T;
scanf("%d", &T);
while(T--){
int n;
scanf("%d", &n);
nx=ny=nz=2;
xs[0]=ys[0]=zs[0]=0;
xs[1]=ys[1]=zs[1]=maxc;
for(int i=0;i<n;++i){
scanf("%d%d%d%d%d%d", &x0[i],&y0[i],&z0[i],&x1[i],&y1[i],&z1[i]);
x1[i]+=x0[i]; y1[i]+=y0[i]; z1[i]+=z0[i];
xs[nx++]=x0[i]; xs[nx++]=x1[i];
ys[ny++]=y0[i]; ys[ny++]=y1[i];
zs[nz++]=z0[i]; zs[nz++]=z1[i];
}
discretize(xs, nx);
discretize(ys, ny);
discretize(zs, nz);
memset(color, 0, sizeof(color));
//将雕塑的组成不封染成solid实心
for(int i=0;i<n;++i){
int sx=pos(xs, nx,x0[i]), ex=pos(xs, nx, x1[i]);
int sy=pos(ys, ny,y0[i]), ey=pos(ys, ny, y1[i]);
int sz=pos(zs, nz,z0[i]), ez=pos(zs, nz, z1[i]);
for(int j=sx;j<ex;++j){
for(int k=sy;k<ey;++k){
for(int l=sz;l<ez;++l){
color[j][k][l]=1;
}
}
}
}
int v, s;
floodfill(v, s);
printf("%d %d\n", s, v);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: