您的位置:首页 > 其它

uva12171 sculpture 离散化 3维bfs求面积体积

2016-08-05 00:28 253 查看
离散化。

状态数组是关键。

求面积利用投影和6个方向就可以解决。

题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=24845

看了很久才看懂,代码是网上找的,注释是自己写的,终于理解透彻了。

离散化>>bfs

求面积:一个实点利用投影和6个方向可以求得。求垂直于遍历方向的面。

求体积:利用一个实点直接求得。//此题不行,需要先计算空气的体积然后相减,空气的体积利用遍历空气求得。

状态数组的使用很是关键。

#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;

int u[6]={0,0,0,0,1,-1};//x的状态
int v[6]={1,-1,0,0,0,0};//y的状态
int w[6]={0,0,1,-1,0,0};//z的状态

struct rec{//用于输入时的值
int x1,y1,z1,x2,y2,z2;
};

struct POINT{//点
int x,y,z;
};

bool vis[103][103][103];//访问过的点
bool loc[103][103][103];//保存墙的点,只保存一个角的点,利用bfs梯度计算
int n,T,ans1,ans2;//面积和体积
int x[103],y[103],z[103];//用于离散化
rec p[103];//保存长方体的值
int numx,numy,numz;//保存最大值,用于最后的输出

int IDX(int aim){//用于返回长方体的位置
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;
}

/*
*因为减一如果探测到的话,那么表示的是投影,面积一样,比如x方向插入那么计算的是垂直的面的面积
*/
int solve(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;
}

void bfs(){
queue<POINT> q;//bfs()
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 now=q.front();
q.pop();
for (int i=0;i<6;i++)
{//6个方向进行bfs
int tx=now.x+u[i];
int ty=now.y+v[i];
int tz=now.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])
{//遇到实点则计算面积,由于有6个方向遍历,所以可以访问完6个面。
ans1+=solve(i,now.x,now.y,now.z);
}
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(){
scanf("%d",&T);
for (int cas=1;cas<=T;cas++){
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[2*i+1]=p[i].x1;//0位不保存值,用于第一个空气遍历
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;//离散化
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;//记录矩形位置,只保存一个角
}
}
}
}
ans1=0;//^2
ans2=0;//^3
bfs();
ans2=x[numx-1]*y[numy-1]*z[numz-1]-ans2;//总体积减去空气体积
printf("%d %d\n",ans1,ans2);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  uva12171