UVA 12171 - Sculpture(雕塑) By SuCicada

    科技2026-02-10  18

    例题6-18 雕塑(Sculpture, ACM/ICPC NWERC 2008, UVa12171) 某雕塑由n(n≤50)个边平行于坐标轴的长方体组成。每个长方体用6个整 数x0,y0,z0,x,y,z表示(均为1~500的整数),其中x0为长方体的顶点中x坐标的最小 值,x表示长方体在x方向的总长度。其他4个值类似定义。你的任务是统计这个雕像的体积 和表面积。注意,雕塑内部可能会有密闭的空间,其体积应计算在总体积中,但从“外部”看 不见的面不应计入表面积。雕塑可能会由多个连通块组成。 Sample Input 2 2 1 2 3 3 4 5 6 2 3 3 4 5 7 1 1 1 5 5 1 1 1 10 5 5 1 1 1 2 1 4 8 2 1 2 4 1 8 5 2 2 1 4 8 1 5 2 4 1 8 3 3 4 1 1 1 Sample Output 188 120 250 250

    本家地址


    关键点:

    构造三维数组space来模拟雕像涂色。我们只从空白处开始遍历联通部分,最后使用总体积和面积减去空白部分的。但是不能使用500*500*500的数组,太大。采用离散化。即将雕像分组,因为最多只有50个方块,所以每个方向最多只会有100个分组。使用map来存储坐标值与space中的方位的对应关系。、之后使用常规bfs方式进行方块遍历。不要用dfs,栈溢出。
    #include<iostream> #include<vector> #include<set> #include<map> #include<algorithm> #include<cstring> #include<queue> using namespace std; class Cube{ public: int xyz[3]; int sss[3]; }; vector<Cube> cubeList; /* site[0] => x site[1] => y site[2] => z 每个map键为坐标原始值,对应的值为space中的坐标值对应的单元格的下标 map<value, index> 通过 对应的坐标点的值去map里得到 space的位置 */ map<int,int> site[3]; /* 每个方向上的原始坐标值,用vector存是为了更快的遍历 */ vector<int> value[3]; /* 因为最多只有50个方块,即每个方向100个边,即最多每个方向会分为100个不定大小的单元格 按照单元格(不定大小)进行分组,存储单元格信息(染色与否) */ int space[105][105][105]; queue<Cube> temp; int getSetIndex(int xyz, int value){ return site[xyz][value]; } long V; // 空白的体积 long S; // 空白的表面积(带外围) int XX,YY,ZZ; // 单元格的每个方向上的数量,即space尺寸 int check(int x,int y,int z){ if(x>=0&&x<XX && y>=0&&y<YY && z>=0&&z<ZZ){ if(space[x][y][z]==1){ return 1; }else if(space[x][y][z]==0){ Cube c; c.xyz[0]=x; c.xyz[1]=y; c.xyz[2]=z; temp.push(c); } return 0; }else{ return -1; } } int bfs(int x,int y,int z){ Cube c; c.xyz[0]=x; c.xyz[1]=y; c.xyz[2]=z; temp.push(c); while(!temp.empty()){ c = temp.front();temp.pop(); x = c.xyz[0]; y = c.xyz[1]; z = c.xyz[2]; if(x>=0&&x<XX && y>=0&&y<YY && z>=0&&z<ZZ){ if(space[x][y][z]==0){ space[x][y][z] = 2; /* 走过了 */ int xs = value[0][x+1] - value[0][x]; int ys = value[1][y+1] - value[1][y]; int zs = value[2][z+1] - value[2][z]; V += xs * ys * zs; int res; res = check(x-1,y,z); S = S + res * ys*zs; // cout<<1<<" "<<res<<" "<<V<<" "<<S<<endl; res = check(x+1,y,z); S = S + res * ys*zs; // cout<<2<<" "<<res<<" "<<V<<" "<<S<<endl; res = check(x,y-1,z); S = S + res * xs*zs; // cout<<3<<" "<<res<<" "<<V<<" "<<S<<endl; res = check(x,y+1,z); S = S + res * xs*zs; // cout<<4<<" "<<res<<" "<<V<<" "<<S<<endl; res = check(x,y,z-1); S = S + res * xs*ys; // cout<<5<<" "<<res<<" "<<V<<" "<<S<<endl; res = check(x,y,z+1); S = S + res * xs*ys; // cout<<6<<" "<<res<<" "<<V<<" "<<S<<endl; } } } return 0; } int run(int x,int y,int z){ return bfs(x,y,z); } void clac(){ /* 从六个面开始过 */ for(int i=0;i<XX;i++){ for(int j=0;j<YY;j++){ run(i,j,0); run(i,j,ZZ-1); } } for(int i=0;i<XX;i++){ for(int k=0;k<ZZ;k++){ run(i,0,k); run(i,YY-1,k); } } for(int j=0;j<YY;j++){ for(int k=0;k<ZZ;k++){ run(0,j,k); run(XX-1,j,k); } } int sumX,sumY,sumZ; if(XX<0) sumX = 0; else sumX = value[0][XX]-value[0][0]; if(YY<0) sumY = 0; else sumY = value[1][YY]-value[1][0]; if(ZZ<0) sumZ = 0; else sumZ = value[2][ZZ]-value[2][0]; int sumS = (sumX * sumY + sumX * sumZ + sumY * sumZ) * 2; int sumV = sumX * sumY * sumZ; cout<<sumS + S<<" "<<sumV-V<<endl; } void init(){ V=S=XX=YY=ZZ=0; cubeList.clear(); for(int i=0;i<3;i++){ site[i].clear(); value[i].clear(); } memset(space,0,sizeof(space)); } int main(){ int T; cin>>T; while(T--){ init(); int N; cin>>N; while(N-- > 0){ Cube b; int x,y,z,xs,ys,zs; cin>>x>>y>>z>>xs>>ys>>zs; b.xyz[0] = x; b.xyz[1] = y; b.xyz[2] = z; b.sss[0] = xs; b.sss[1] = ys; b.sss[2] = zs; /* 存map */ site[0][x] = 0; site[1][y] = 0; site[2][z] = 0; site[0][x+xs] = 0; site[1][y+ys] = 0; site[2][z+zs] = 0; /* 存cube list */ cubeList.push_back(b); } /* map 赋下标, 因为先存到了map中,所以作为键的坐标值就已经是排好序的了 */ for(int i=0;i<3;i++){ map<int,int>::iterator iter; /* 第一面的方块用空白预先填充, 即用空白包裹雕塑一半 */ int n = 0; for(iter=site[i].begin(); iter!=site[i].end(); iter++){ /* index -> value */ value[i].push_back(iter->first); /* value -> index */ iter->second = n; n++; } } /* 单元格数, 比点数少一 */ XX = value[0].size()-1; YY = value[1].size()-1; ZZ = value[2].size()-1; /* space 涂色*/ for(int i=0;i<cubeList.size();i++){ /* 记录xyz 的开始和结束 的下标 */ int start[3]; int end[3]; for(int ii=0;ii<3;ii++){ start[ii] = getSetIndex(ii, cubeList[i].xyz[ii]); end[ii] = getSetIndex(ii, cubeList[i].xyz[ii] + cubeList[i].sss[ii]); } /* 涂色 */ for(int xi=start[0]; xi<end[0]; xi++){ for(int yi=start[1]; yi<end[1]; yi++){ for(int zi=start[2]; zi<end[2]; zi++){ space[xi][yi][zi] = 1; } } } } clac(); } return 0; } // AC at 2020/09/12

    ps:这道题十分美妙。辗转波折,所幸做出,十分感谢。

    Processed: 0.014, SQL: 9