UVa 12171 Sculpture
2015-12-25 12:33
239 查看
题目大意:有个由n个(n<=50)长方体组成的雕塑,现在给出这n个长方体的“左下角”坐标(x,y,z都最小)和x,y,z,方向上的长度,要求算出雕塑的表面积(从外面看的到的,里面的不算),体积(内部的空心也算雕塑的体积)。
思路:先离散化,之后怎么求表面积呢?若是对长方体做floodfill会把雕塑的内表面积也算进去,可以考虑对空气做floodfill。具体是先扩展区域,用离散化把整个区域分成多个有限区域,每个区域中的状态(是雕塑还是空气)是一致的,且每个区域都是长方体,然后对空气floodfill把他们的体积累加起来,如果碰到雕塑则把他们的接触面积累加起来。最后,累加的接触面就是雕塑的外表面,整个区域的体积减去累加起来的空气体积就是雕塑的体积。
代码基本上是照着网上的打下来的:参考代码
思路:先离散化,之后怎么求表面积呢?若是对长方体做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; }
相关文章推荐
- Java中字节与对象之间的转换
- HihoCoder 1014 : Trie树
- 《代码阅读方法与实践》阅读笔记二
- linux内核参数注释与优化
- 创业为什么这么难?
- CocoaPods的安装配置 10.11
- 10、桥接模式(Bridge)
- 微信支付基本流程
- Xj002班2015年12月25日作业及课堂总结
- freemarker的TemplateExceptionHandler使用
- Android ActionBar基本用法
- storyboard传值
- centos6搭建本地openstack软件源
- 《代码阅读方法与实现》阅读笔记三
- Android 解压文件工具类
- 【DOM学习笔记 Unit02】
- chrome安装postman
- web系统高速发展时的海量数据技术架构
- Sublime Text2 快捷键汇总
- Java API —— File类