12171 Sculpture 離散化,網格與點的轉化
阿新 • • 發佈:2019-02-14
某雕塑由 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;
}