题意:
给定n个立方体的一个顶点坐标和3边长度, 问这些立方体组成的雕塑的表面积和体积, 坐标都是整数,n最大为50, 最大为500, 边长最大也是500。
分析:
继UVa221后又一道离散化
首先先深入理解一下离散化: (转自 http://www.cnblogs.com/jerryRey/p/4599388.html)
先来看一个问题:给你以下的网格,你需要多少空间去存储红点区间的信息呢?
只需要图上所示的1,2,3,4个点就足够表示红点所在区间了,为什么不是一个区间的第一个红点和最后一个红点呢?(如果这样记录的话则必须加一区间点,记录区间内部信息,因为端点可能是两个区间的交集而区间内可能只被操作了一次)这样做的好处是空白区域的长度也能轻易计算出来。
因此离散化的核心在于以点代表区间。
对于本题, 如果直接建一个1000*1000*1000的数组进行floodfill , 方法是可行的, 但是从数据上看可能会爆内存+超时, 因为这里数据规模已经到了1e9.
所以我们需要离散化出我们要用的坐标, 对于50个立方体来说, 我们每一个维度(xyz)最大会有50*2 = 100个不同的坐标, 那么我们就可以把这些坐标的区间段记录下来, 这些区间段的性质都是一样的(要么没有东西, 要么是立方体), 所以我们就可以把一个区间离散化为一个点, 然后将这些点填入一个100*100*100的数组做floodfill (数据规模1e6)。
因为本题还有有很多细节的地方, 所以我没有独立编程去实现, 贴一个对刘汝佳代码注释过的代码。
1 #include<cstdio> 2 #include<cstring> 3 #include<queue> 4 #include<algorithm> 5 using namespace std; 6 const int maxn = 50 +5 ; 7 const int maxc = 1000 + 1; 8 9 //原来的数据 10 int n, x0[maxn], x1[maxn], y0[maxn], y1[maxn], z0[maxn], z1[maxn]; 11 12 //离散化 (将每个线段离散为一个点) 13 int nx, ny, nz; 14 int xs[maxn*2], ys[maxn*2], zs[maxn*2]; 15 16 //六个方向 如果是xz面看的话 就是 右左前后上下 17 const int dx[] = {1,-1,0,0,0,0}; 18 const int dy[] = {0,0,1,-1,0,0}; 19 const int dz[] = {0,0,0,0,1,-1}; 20 21 //离散化数组,每一个点都是代表原来的一个线段(不一定是原来的矩形, 可能是矩形的一部分), 在这个坐标内floodfill 22 int color[maxn*2][maxn*2][maxn*2]; 23 24 // 25 struct cube{ 26 int x, y, z; //只要有xyz这个点 , 就能在color数组内对应空气或者实体 27 cube(int x = 0, int y = 0, int z = 0): x(x) , y(y) , z(z){} 28 bool valid() const{ 29 //每个点的左闭右开区间代表一个线段, 而且最后一个点就是范围极限(它不代表一个线段), 所以范围应该是[0, 最后一个点的前一个] 30 //下标从0开始 一直到 nx - 1 个点 31 return x >= 0 && x < nx - 1 && y >= 0 && y < ny-1 && z>=0 && z < nz -1; 32 } 33 34 bool solid() const{ 35 //判断这个点代表的是空气还是实体 36 return color[x][y][z] == 1; 37 } 38 39 bool getvis() const{ 40 //判断是否被访问过 41 return color[x][y][z] == 2; 42 } 43 44 void setvis() const{ 45 color[x][y][z] = 2; 46 } 47 //访问他的邻居 访问要先判断是否 valid 48 cube neighbor(int dir) const{ 49 return cube(x+dx[dir], y+dy[dir], z+dz[dir]); 50 } 51 int volume() const{ 52 //要计算这个color点的体积, 要重新找回这个color点原始的数据 53 return (xs[x+1] - xs[x]) * (ys[y+1] -ys[y]) * (zs[z+1]-zs[z]); 54 } 55 int area(int dir) const{//计算表面积 56 //想象一下 如果遍历过程中向上碰到solid, 那么说明这肯定是一个 xy型的面, 所以可以加上x*y 57 if(dx[dir] != 0) return (ys[y+1] - ys[y]) * (zs[z+1]-zs[z]); 58 else if(dy[dir] != 0) return (xs[x+1] - xs[x]) * (zs[z+1] - zs[z]); 59 return (xs[x+1] - xs[x]) * (ys[y+1] - ys[y]); 60 } 61 }; 62 63 void discretize(int* x, int& n){ 64 sort(x,x+n); //默认升序 65 n = unique(x,x+n) - x; // 这样就可以求出有多少个不同的元素 66 } 67 int ID(int* x, int n, int x0){//使原来矩形的数据对应离散化数组的下标 68 return lower_bound(x, x+n, x0) - x; //返回一个等于x0的下标 69 } 70 71 void floodfill(int&v , int& s){ 72 v = 0; 73 s = 0; 74 cube c; 75 c.setvis(); 76 queue<cube> q;//碰到空气就入队, 碰到solid计算表面积 77 q.push(c); 78 while(!q.empty()){ 79 cube c = q.front(); q.pop(); 80 v += c.volume(); //出队空气的体积 81 for(int i = 0; i < 6; i++){ 82 cube c2 = c.neighbor(i); 83 if(!c2.valid()) continue; 84 if(c2.solid()) s += c.area(i); 85 else if(!c2.getvis()){ 86 c2.setvis(); 87 q.push(c2); 88 } 89 } 90 } 91 v = maxc*maxc*maxc - v; 92 } 93 94 int main(){ 95 int T; 96 scanf("%d", &T); 97 while(T--){ 98 nx = ny = nz = 2; 99 xs[0] = ys[0] = zs[0] = 0;//给定下界 让空气可以严格包围矩形 100 xs[1] = ys[1] = zs[1] = maxc; // 同上 101 102 scanf("%d", &n); 103 for(int i = 0; i < n ;i++){ 104 scanf("%d %d %d %d %d %d", &x0[i], &y0[i], &z0[i], &x1[i], &y1[i], &z1[i]); 105 x1[i] += x0[i], y1[i] += y0[i], z1[i] += z0[i]; 106 107 xs[nx++] = x0[i], xs[nx++] = x1[i]; 108 ys[ny++] = y0[i], ys[ny++] = y1[i]; 109 zs[nz++] = z0[i], zs[nz++] = z1[i]; 110 } 111 discretize(xs,nx);//离散化, 传入一个数组坐标和一个应用变量, 去重输出有多少段 112 discretize(ys,ny); 113 discretize(zs,nz); 114 memset(color, 0, sizeof(color));//初始化color 准备用坐标填入 115 for(int i = 0; i < n; i++){ 116 int X1 = ID(xs,nx,x0[i]), X2 = ID(xs,nx,x1[i]); 117 int Y1 = ID(ys,ny,y0[i]), Y2 = ID(ys,ny,y1[i]); 118 int Z1 = ID(zs,nz,z0[i]), Z2 = ID(zs,nz,z1[i]); 119 //左开右闭区间代表线段 120 for(int X = X1; X < X2; X++){ 121 for(int Y = Y1; Y < Y2; Y++){ 122 for(int Z = Z1; Z < Z2; Z++){ 123 color[X][Y][Z] = 1; 124 } 125 } 126 } 127 } 128 int v, s; 129 floodfill(v, s); 130 printf("%d %d\n",s,v); 131 } 132 }
时间: 2024-10-06 06:08:40