https://cn.vjudge.net/problem/UVA-12171
某雕塑由 n (n<=50) 个边平行于坐标轴、坐标在1到1000内的的长方体组成。统计这个雕像的体积和表面积。注意,雕像内部可能会有密闭的空间,其体积应该算在总体积中,而其面积不算在表面积中。
分析
注意这道题的基本单位是体积为1立方单位的小方块,所以可以把每个长方体都看成对若干小方块的填充。未填充的块视为空气,则:
体积 = 总空间体积 - 外部连通的空气体积
外表面积 = 外部连通的空气与雕塑的接触面面积之和
注意题目中给出的都是点的坐标而不是方块的坐标,为了方便地判断连通性与体积,应当将长方体的边界点表示转换成小方块的坐标表示。
编号(i,j,k)表示x在(i,i+1),y在(j,j+1),z在(k,k+1)内的一个小方块。每个小方块的体积为1,每个面的面积为1。
举例来说,长方体(1,2,3,1,2,3)表示x在(1,2),y在(2,4),z在(3,6)内,它填充的小方块包括:(1,2,3),(1,3,3),(1,2,4),(1,3,4),(1,2,5),(1,3,5).
如果这样做的话,小方块最多有1000*1000*1000=1e9个,显然无法处理的,而每个维度上最多只有50*2=100个坐标,所以可以离散化,只需要处理最多100*100*100=1e6个小方块。
对每个维度的所有点坐标分别进行离散化,将映射和逆映射分别保存在map<int,int> dct和数组int idct[3][100]中。
现在,编号(i,j,k)的“小方块”表示的区域为
记
则体积为
,x方向的面积为
,y方向的面积为
,z方向的面积为
。
数据结构
map<int,int> dct[3]; //从原始坐标到离散化坐标,3个维度,dct = DisCreTization(离散化)
int did[3][100]; //离散化后每个区域的长度,3个维度,didct = Difference Inverse Dct(逆离散化的差分数组)
int fil[100][100][100]; //表“小方块”是否被填充及是否被访问,0表示未被访问的空气,1表示被填充,-1表示已被访问的空气
int cub[50][6]; //原始数据,长方体的六维,cub = cuboid
int lim[3]; //每个维度的数据个数,也即方块个数,lim = limit
算法
- 初始化数据结构,读入数据。
- 建立离散化映射,将数据离散化,填充小方块。
- floodfill过程中计算体积与表面积。
- 输出。
debug
最大边界是1000,添加空气只添加了1000,改成1024后过题。
/* LittleFall : Hello! */
#include <bits/stdc++.h>
//using namespace std;
using ll = long long; inline int read();
const int M = 128, MOD = 1000000007;
std::map<int,int> dct[3];
int did[3][M];
int lim[3];
int cub[M][6];
char fil[M][M][M];
void init()
{
//init
for(int i=0;i<3;++i) dct[i].clear();
memset(did,0,sizeof(did));
memset(lim,0,sizeof(lim));
memset(cub,0,sizeof(cub));
memset(fil,0,sizeof(fil));
//read
int n = read();
for(int i=1;i<=n;++i)
{
for(int j=0;j<3;++j) cub[i][j] = read();
for(int j=3;j<6;++j) cub[i][j] = cub[i][j-3] + read();
}
//discretization
for(int i=1;i<=n;++i)
for(int d=0;d<3;++d) //维度
dct[d][cub[i][d]], dct[d][cub[i][d+3]];
for(int d=0,cnt;d<3;++d)
{
dct[d][0], dct[d][1024];
cnt = 0;
for(auto &x : dct[d])
x.second = ++cnt;
cnt = 0;
for(auto x : dct[d])
{
did[d][cnt] += x.first;
did[d][++cnt] = -x.first;
}
lim[d] = cnt - 1;
}
//fill
for(int i=1;i<=n;++i)
{
int xl = dct[0][cub[i][0]], xr = dct[0][cub[i][3]];
int yl = dct[1][cub[i][1]], yr = dct[1][cub[i][4]];
int zl = dct[2][cub[i][2]], zr = dct[2][cub[i][5]];
for(int x=xl;x<xr;++x)
for(int y=yl;y<yr;++y)
for(int z=zl;z<zr;++z)
fil[x][y][z] = 1;
}
}
const int go[6][3]={{1,0,0},{-1,0,0},{0,1,0},{0,-1,0},{0,0,1},{0,0,-1}};
ll vol, are;
void dfs(int x,int y,int z)
{
fil[x][y][z] = -1;
vol -= did[0][x] * did[1][y] * did[2][z];
for(int k=0;k<6;++k)
{
int nx = x+go[k][0], ny = y+go[k][1], nz = z + go[k][2];
if(nx>=1 && nx<=lim[0] && ny>=1 && ny<=lim[1] && nz>=1 && nz<=lim[2])
{
if(fil[nx][ny][nz]==0)
dfs(nx,ny,nz);
else if(fil[nx][ny][nz]==1)
{
ll tare = 1;
if(k/2 != 0) tare *= did[0][x];
if(k/2 != 1) tare *= did[1][y];
if(k/2 != 2) tare *= did[2][z];
are += tare;
}
}
}
}
int main(void)
{
#ifdef _LITTLEFALL_
freopen("in.txt","r",stdin);
#endif
int T = read();
while(T--)
{
init();
vol = 1<<30, are = 0;
dfs(1,1,1);
printf("%lld %lld\n",are,vol );
}
return 0;
}
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}