UVa Sculpture(离散化 floodfill)

题意:

给定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

UVa Sculpture(离散化 floodfill)的相关文章

UVa 12171 (离散化 floodfill) Sculpture

题意: 三维空间中有n个长方体组成的雕塑,求表面积和体积. 分析: 我们可以在最外边加一圈“空气”,然后求空气的连通块的体积,最后用总体积减去即是雕塑的体积. 还有一个很“严重”的问题就是5003所占的空间太大,因此需要离散化.而在计算体积和表面积的时候要用原坐标. 离散化以后的坐标分别保存在xs.ys.zs,坐标为(x, y, z)的格子代表([xs[x], ys[y], zs[z]) ~ (xs[x+1], ys[y+1], zs[z+1]) 这一个小长方体. 这个题的难度对我来说属于大概思

UVA12171-Sculpture(离散化+floodfill)

Problem UVA12171-Sculpture Accept: 196  Submit: 1152 Time Limit: 3000 mSec Problem Description Imagine a box, made of copper plate. Imagine a second one, intersecting the rst one, and several others, intersecting each other (or not). That is how the

UVA 572 Oil Deposits油田(DFS求连通块)

UVA 572     DFS(floodfill)  用DFS求连通块 Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Description Due to recent rains, water has pooled in various places in Farmer John's field, which is represented by a rectangle of N x M

hdu 2771(uva 12171) Sculpture bfs+离散化

题意: 给出一些边平行于坐标轴的长方体,这些长方体可能相交.也可能相互嵌套.这些长方体形成了一个雕塑,求这个雕塑的整体积和表面积. 题解: 最easy想到直接进行bfs或者dfs统计,但此题的麻烦之处在于求整个雕塑的外表面积和雕塑内部可能出现四个长方体所搭成的空心.空心不能计算到表面积中,可是计算整体积却要计入,于是直接bfs或者dfs不优点理.于是,能够想到直接统计整个雕塑外围的全部小方块.就可以非常方便地求出雕塑地表面积和体积(雕塑地整体积==整个空间地体积-外围想方块的体积),另一点就是因

UVa 221城市正视图(离散化)

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=157 题意:输入建筑物的x,y坐标,宽度,深度和高度,输出从南向北看时能看到的建筑物. 这道题需要用到离散化,将所有建筑物物的左右边界坐标存储起来,然后排序去重,那么任意两个相邻x坐标形成的区间要么是可见的,要么就是不可见的.这样只需在这个区间内任选一点(如中点),当该建筑物可见时,首先它的

UVa 221 Urban Elevations 城市正视图 离散化初步 无限化有限

转载请注明: 仰望高端玩家的小清新 http://www.cnblogs.com/luruiyuan/ 题目大意: 题目传送门:UVa 221 Urban Elevations 给出城市中建筑物的x, y 坐标的最小值:x,y , 再给出其以左下角为坐标原点的关于x轴.y轴上的长度 w, 和 d,最后给出建筑物的高度 h,将建筑物的正视图中,能够看到的建筑物的id打印出来:要求先打印x小的,当x相同时,打印y小的.为了简化,假定建筑物都是长方体.同时,每个输出之间要用一个空行隔开 One bla

【map离散化+打表】UVA 11995 I Can Guess the Data Structure!

[map离散化+打表]UVA 11995 I Can Guess the Data Structure! map关联容器:有序 + 映射,查找的复杂度O(nlogn) 题目大意 给你n个数构成的数组,求数v第k次出现的下标值(下标从1开始) – 说一下思路 这题很显然要打表预处理,关键是怎么打这张表 1.首先我们观察到v很大,开一个二维数组data[v][k]肯定存储不了,所以用map离散化(自动有序编号,避免空间浪费) 2.data[v]肯定是一个变长的数组,存储数据v出现0,1,2次--的下

uva oj 12171(hdu 2771)[离散化]sculptrue

以前对离散化的理解不够,所以把端点和区间区分来考虑但是做完这题以后有了新的认识: 先来看一个问题:给你以下的网格,你需要多少空间去存储红点区间的信息呢? 只需要图上所示的1,2,3,4个点就足够表示红点所在区间了,为什么不是一个区间的第一个红点和最后一个红点呢?(如果这样记录的话则必须加一区间点,记录区间内部信息,因为端点可能是两个区间的交集而区间内可能只被操作了一次)这样做的好处是空白区域的长度也能轻易计算出来. 为了计算总区间两端空白的长度,增加A和B点. 原数据找离散后的值直接二分,没必要

UVA 11983 Weird Advertisement 线段树+离散化+扫描线

有点像HDU 3642的强化版.给你N个矩形的坐标,问题平面上被k个不同的矩形覆盖的面积是多少. 当初HDU 3642 是直接一个一个手写的,这里的k虽然说只有10,合并过成一个一个手写也是相当蛋疼的,不过仔细想一下,不难推出一般性的关系,然后直接用循环搞就好了.不过我还是因为有个地方忘记初始化WA了2发,真是弱o(╯□╰)o 注意每个房子代表一个点,而我们要把他转化成线段,对坐标进行一些简单的变换即可. #include <cstdio> #include <cstring> #