【题解】UVA - 12171 Sculpture 离散化,网格与点的转化

版权声明:欢迎评论交流,转载请注明原作者。 https://blog.csdn.net/m0_37809890/article/details/83539410

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 ( i d c t 0 [ i ] , i d c t 0 [ i + 1 ] ) , y ( i d c t 1 [ j ] , i d c t 1 [ j + 1 ] ) , z ( i d c t 2 [ k ] , i d c t 2 [ k + 1 ] ) x在(idct_0[i],idct_0[i+1]),y在(idct_1[j],idct_1[j+1]),z在(idct_2[k],idct_2[k+1])内。
d 0 = ( i d c t 0 [ i + 1 ] i d c t 0 [ i ] ) , d 1 = ( i d c t 1 [ j + 1 ] i d c t 1 [ j ] ) , d 2 = ( i d c t 2 [ k + 1 ] i d c t 2 [ k ] ) d_0 = (idct_0[i+1]-idct_0[i]),d_1=(idct_1[j+1]-idct_1[j]),d_2=(idct_2[k+1]-idct_2[k])
则体积为 d 0 d 1 d 2 d_0*d_1*d_2 ,x方向的面积为 d 1 d 2 d_1*d_2 ,y方向的面积为 d 0 d 2 d_0*d_2 ,z方向的面积为 d 0 d 1 d_0*d_1

数据结构

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

算法

  1. 初始化数据结构,读入数据。
  2. 建立离散化映射,将数据离散化,填充小方块。
  3. floodfill过程中计算体积与表面积。
  4. 输出。

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

猜你喜欢

转载自blog.csdn.net/m0_37809890/article/details/83539410