UVa 12171 Sculpture

题目大意:有个由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;
 	
 }

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值