UVA - 12171 Sculpture

/*
  A. 这题用到了之前做过的一些题的一些思想:
  
  例如:
  
  1. 之前做过的 UVA - 1103 Ancient Messages ( http://blog.csdn.net/mofushaohua_ln/article/details/78162277 )
  
  两题十分相似之处在于,都是连通块问题,且都要在最外围,加上一圈“空气”,以使得所有空气格子得以连通
  
  2. 之前做过的 UVA - 221 Urban Elevations ( http://blog.csdn.net/mofushaohua_ln/article/details/77799245 )
  
  两题都用到了坐标离散化的思想,来减少所需单元格的数目
  不过需要注意的是,floodfill时,运用离散化后的坐标来处理连通块,是没有问题的。但是,在统计表面积和体积时,一定要用原始坐标,否则必定WA
  
  B. 该题主要思路见小白书 P172
  不考虑雕塑本身,而考虑“空气”,在网格周围加一圈“空气”(目的时为了让所有空气格子连通),然后做一次 floodfill,即可得到空气的 “内表面积” 和体积,这个表面积就是雕塑的外表面积,雕塑体积等于总体积减去空气体积
  
  floodfill 时直接使用离散化后的新坐标,但在统计表面积和体积时则需要使用原始坐标
  
*/


#include <iostream>
#include <algorithm>
#include <queue>
#include <cstring>
#define rep(i, n) for ( int i = 0; i < (n); i++ )
using namespace std;

const int N = 50 + 5;
const int C = 1e3 + 1;

int n, x0[N], y0[N], z0[N], x1[N], y1[N], z1[N];

// 离散化后的坐标
int nx, ny, nz;
int xs[N * 2], ys[N * 2], zs[N * 2];

// 种子填充
const int dx[] = { 1, -1, 0, 0, 0, 0 };
const int dy[] = { 0, 0, 1, -1, 0, 0 };
const int dz[] = { 0, 0, 0, 0, 1, -1 };
int color[N * 2][N * 2][N * 2];

struct Cell
{
	int x, y, z;
	Cell (int x = 0, int y = 0, int z = 0) : x(x), y(y), z(z)
	{
	}
	
	bool valid() const
	{
		return x >= 0 && x < nx - 1 && y >= 0 && y < ny - 1 && z >= 0 && z < nz - 1;
	}
	
	bool solid() const
	{
		return color[x][y][z] == 1; // solid
	}
	
	bool getVis() const
	{
		return color[x][y][z] == 2; // visited
	}
	
	void setVis() const
	{
		color[x][y][z] = 2;
	}
	
	Cell neighbour (int dir) const
	{
		return Cell( x + dx[dir], y + dy[dir], z + dz[dir] );
	}
	
	int getVolume() const
	{
		return ( xs[x + 1] - xs[x] ) * ( ys[y + 1] - ys[y] ) * ( zs[z + 1] - zs[z] );
	}
	
	int getArea(int dir) const
	{
		if (dx[dir]) return ( ys[y + 1] - ys[y] ) * ( zs[z + 1] - zs[z] );
		if (dy[dir]) return ( xs[x + 1] - xs[x] ) * ( zs[z + 1] - zs[z] );
		return ( xs[x + 1] - xs[x] ) * ( ys[y + 1] - ys[y] );
	}
};

void discretize (int* x, int& n) // 坐标离散化
{
	sort(x, x + n);
	n = unique(x, x + n) - x;
}

int ID (int *x, int n, int x0)
{
	return lower_bound(x, x + n, x0) - x;
}

void FloodFill(int &v, int &s)
{
	v = s = 0;
	Cell c;
	c.setVis();
	queue<Cell> q;
	q.push(c);
	
	while (!q.empty())
	{
		Cell c = q.front();
		q.pop();
		v += c.getVolume();
		
		rep(i, 6)
		{
			Cell c2 = c.neighbour(i);
			if (!c2.valid()) continue;
			if (c2.solid()) s += c.getArea(i);
			else if (!c2.getVis())
			{
				c2.setVis();
				q.push(c2);
			}
		}	
	}
	v = C * C * C- v;
}

int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		nx = ny = nz = 2;
		xs[0] = ys[0] = zs[0] = 0;
		xs[1] = ys[1] = zs[1] = C;
		
		cin >> n;
		rep(i, n)
		{
			cin >> x0[i] >> y0[i] >> z0[i] >> x1[i] >> y1[i] >> z1[i];
			
			x1[i] += x0[i]; y1[i] += y0[i]; z1[i] += z0[i];
			xs[nx++] = x0[i]; xs[nx++] = x1[i];
			ys[ny++] = y0[i]; ys[ny++] = y1[i];
			zs[nz++] = z0[i]; zs[nz++] = z1[i];
		}
		discretize(xs, nx);
		discretize(ys, ny);
		discretize(zs, nz);
		
		// paint
		memset( color, 0, sizeof(color) );
		
		rep(i, n)
		{
			int X1 = ID ( xs, nx, x0[i] ), X2 = ID ( xs, nx, x1[i] );
			int Y1 = ID ( ys, ny, y0[i] ), Y2 = ID ( ys, ny, y1[i] );
			int Z1 = ID ( zs, nz, z0[i] ), Z2 = ID ( zs, nz, z1[i] );
			
			for (int X = X1; X < X2; X++)
				for (int Y = Y1; Y < Y2; Y++)
					for (int Z = Z1; Z < Z2; Z++)
					{
						color[X][Y][Z] = 1;
					}
		}
		
		int v, s;
		FloodFill(v, s);
		cout << s << " " << v << endl;	
	}
}

转载于:https://www.cnblogs.com/mofushaohua/p/7789390.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值