• UVA-12171 雕塑 题解答案代码 算法竞赛入门经典第二版


    GitHub - jzplp/aoapc-UVA-Answer: 算法竞赛入门经典 例题和习题答案 刘汝佳 第二版

    这道题目在《算法竞赛入门经典第二版》书中标注了星号,也是第一道出现星号的题目。

    第一次遇到星号题,我还是有点害怕的。但是实际上没有那么难,就是有点麻烦而已。

    思路:

    题目本身比较好理解,实际上就是“三维图”的遍历,一个结点的周围节点是6个而已。

    由于中间的空心不计算,因此求体积和表面积时,只需要求外围的体积/面积即可。参考之前做过的UVA-1103  古代象形符号 题目,图片外围加一层边框,保证所有外围空白区域都是联通的。

    坐标理论上的最大值是500 * 500 * 500。直接用这么大的图遍历很可能超时,因此参考之前UVA-221 城市正视图 题目,对坐标进行去重和转换,遍历图使用新坐标,计算体积和面积时使用旧坐标。

    即使转换了坐标,图最大依旧可以达到100 * 100 * 100,使用dfs还是会爆栈,所以这里使用了bfs即可。(这个题目遍历顺序无所谓的)

    下面描述的是我的做法,不一定有普适性:

    至少要遍历图两次,第一次求哪些结点是外表面,第二次计算体积和表面积。

    对于一个方格,起点的格子是包含在方格内的,但是终点的结点对应的格子是不包含在方格内的,因此在构建图的时候,就要表明哪些结点属于方格的终点,这些点不包含在方格内。还要注意重叠点的情况,如果这个终点属于其他方格内部结点,那么就要被覆盖为内部结点。

    如果不标注,就会发生这种情况:

     2是方格的终点,2-3中间的区域应该是空的。但是在后续计算面积和体积时,因为2和3都有值,因此认为1-4是一片整个方格。中间的间隔没有被考虑到,因此计算错误。

    计算体积时,是用整个500 * 500 * 500的体积减去外围空白区域的体积来计算的,因此这时候需要在计算出的新坐标轴中加入0(最小点)和500(最大点),我实际取的值是505。

    计算面积时,由于是精确到每个区域来计算面积,因此会有两种模式:

    1. 本身为终点。

    这时候就要找该点上部3个面哪些点属于图形内部(本身为终点,不需要考虑下部),确定哪几个面属于终点的面。

    2. 本身为外部空白区域贴着的内部结点。这时候就要确定周围哪些结点是属于外部空白区域,以确认哪些是接触面。为了不重复计算,也只是计算上部3个面。因为如果是下部三个面存在接触面,则对应的下部的点就是终点,终点会去计算那些面。

    一定要确定是内外接触面,注意这个情况:

     里面的空白不要被认错成外部空白区域即可。

    AC代码

    1. #include
    2. #include
    3. #include
    4. #include
    5. using namespace std;
    6. #define MAXN 505
    7. #define MAXM 105
    8. const int stepX[6] = {1,-1,0,0,0,0};
    9. const int stepY[6] = {0,0,1,-1,0,0};
    10. const int stepZ[6] = {0,0,0,0,1,-1};
    11. struct Box {
    12. int x0, y0, z0;
    13. int x, y, z;
    14. };
    15. struct Point {
    16. int x, y, z;
    17. };
    18. Box arrBox[55];
    19. int boxlen;
    20. int axisX[MAXM];
    21. int axisY[MAXM];
    22. int axisZ[MAXM];
    23. int lenx, leny, lenz;
    24. int space[MAXM][MAXM][MAXM];
    25. bool findSpace[MAXM][MAXM][MAXM];
    26. int volume, area;
    27. void clear() {
    28. memset(arrBox, 0, sizeof(arrBox));
    29. boxlen = 0;
    30. memset(axisX, 0, sizeof(axisX));
    31. memset(axisY, 0, sizeof(axisY));
    32. memset(axisZ, 0, sizeof(axisZ));
    33. lenx = 0;
    34. leny = 0;
    35. lenz = 0;
    36. memset(space, 0, sizeof(space));
    37. volume = 0;
    38. area= 0;
    39. memset(findSpace, 0, sizeof(findSpace));
    40. }
    41. void input() {
    42. int i;
    43. Box b;
    44. scanf("%d", &boxlen);
    45. for(i = 0; i < boxlen; ++i) {
    46. scanf("%d %d %d %d %d %d", &b.x0, &b.y0, &b.z0, &b.x, &b.y, &b.z);
    47. b.x += b.x0;
    48. b.y += b.y0;
    49. b.z += b.z0;
    50. arrBox[i] = b;
    51. }
    52. }
    53. void handleAxis() {
    54. map<int, int> mpx, mpy, mpz;
    55. int i, j;
    56. for(i = 0; i < boxlen; ++i) {
    57. mpx[arrBox[i].x0] = 1;
    58. mpx[arrBox[i].x] = 1;
    59. mpy[arrBox[i].y0] = 1;
    60. mpy[arrBox[i].y] = 1;
    61. mpz[arrBox[i].z0] = 1;
    62. mpz[arrBox[i].z] = 1;
    63. }
    64. i = 1;
    65. for(auto ip = mpx.begin(); ip != mpx.end(); ++ip, ++i) {
    66. mpx[ip->first] = i;
    67. axisX[i] = ip->first;
    68. }
    69. lenx = i;
    70. axisX[lenx] = MAXN;
    71. axisX[lenx + 1] = MAXN;
    72. i = 1;
    73. for(auto ip = mpy.begin(); ip != mpy.end(); ++ip, ++i) {
    74. mpy[ip->first] = i;
    75. axisY[i] = ip->first;
    76. }
    77. leny = i;
    78. axisY[leny] = MAXN;
    79. axisY[leny + 1] = MAXN;
    80. i = 1;
    81. for(auto ip = mpz.begin(); ip != mpz.end(); ++ip, ++i) {
    82. mpz[ip->first] = i;
    83. axisZ[i] = ip->first;
    84. }
    85. lenz = i;
    86. axisZ[lenz] = MAXN;
    87. axisZ[lenz + 1] = MAXN;
    88. for(i = 0; i < boxlen; ++i) {
    89. arrBox[i].x0 = mpx[arrBox[i].x0];
    90. arrBox[i].x = mpx[arrBox[i].x];
    91. arrBox[i].y0 = mpy[arrBox[i].y0];
    92. arrBox[i].y = mpy[arrBox[i].y];
    93. arrBox[i].z0 = mpz[arrBox[i].z0];
    94. arrBox[i].z = mpz[arrBox[i].z];
    95. }
    96. }
    97. bool isEdge(int a) {
    98. return a / 1000 == 1;
    99. }
    100. void handleSpace() {
    101. int i, j, k, a;
    102. for(a = 0; a < boxlen; ++a) {
    103. for(i = arrBox[a].x0; i <= arrBox[a].x; ++i) {
    104. for(j = arrBox[a].y0; j <= arrBox[a].y; ++j) {
    105. for(k = arrBox[a].z0; k <= arrBox[a].z; ++k) {
    106. if(i == arrBox[a].x || j == arrBox[a].y || k == arrBox[a].z) {
    107. if(space[i][j][k] != 1) {
    108. space[i][j][k] = 1001;
    109. continue;
    110. }
    111. }
    112. space[i][j][k] = 1;
    113. }
    114. }
    115. }
    116. }
    117. }
    118. void getBorder() {
    119. Point p;
    120. int i, a, b, c;
    121. queue qu;
    122. space[0][0][0] = 2;
    123. qu.push({0, 0, 0});
    124. while(!qu.empty()) {
    125. p = qu.front();
    126. qu.pop();
    127. for(i = 0; i < 6; ++i) {
    128. a = p.x + stepX[i];
    129. b = p.y + stepY[i];
    130. c = p.z + stepZ[i];
    131. if(a < 0 || a > lenx || b < 0 || b > leny || c < 0 || c > lenz) continue;
    132. if(space[a][b][c] % 1000 == 2) continue;
    133. if(space[a][b][c] == 0) space[a][b][c] = 2;
    134. if(isEdge(space[a][b][c])) space[a][b][c] = 1002;
    135. if(space[a][b][c] % 1000 == 2)
    136. qu.push({a, b, c});
    137. }
    138. }
    139. }
    140. int getVolumeOne(int a, int b, int c) {
    141. return (axisX[a+1] - axisX[a]) * (axisY[b+1] - axisY[b]) * (axisZ[c+1] - axisZ[c]);
    142. }
    143. int getAreaOne(int a, int b, int c) {
    144. int sum = 0;
    145. if(isEdge(space[a][b][c])) {
    146. if(space[a-1][b][c] == 1) {
    147. sum += (axisY[b+1] - axisY[b]) * (axisZ[c+1] - axisZ[c]);
    148. }
    149. if(space[a][b-1][c] == 1) {
    150. sum += (axisX[a+1] - axisX[a]) * (axisZ[c+1] - axisZ[c]);
    151. }
    152. if(space[a][b][c-1] == 1) {
    153. sum += (axisX[a+1] - axisX[a]) * (axisY[b+1] - axisY[b]);
    154. }
    155. }
    156. if(space[a][b][c] == 1) {
    157. if(space[a-1][b][c] % 1000 == 2) {
    158. sum += (axisY[b+1] - axisY[b]) * (axisZ[c+1] - axisZ[c]);
    159. }
    160. if(space[a][b-1][c] % 1000 == 2) {
    161. sum += (axisX[a+1] - axisX[a]) * (axisZ[c+1] - axisZ[c]);
    162. }
    163. if(space[a][b][c-1] % 1000 == 2) {
    164. sum += (axisX[a+1] - axisX[a]) * (axisY[b+1] - axisY[b]);
    165. }
    166. }
    167. return sum;
    168. }
    169. void getVolumeAndArea() {
    170. volume = 0;
    171. area = 0;
    172. Point p;
    173. int i, a, b, c;
    174. queue qu;
    175. findSpace[0][0][0] = true;
    176. volume += getVolumeOne(0, 0, 0);
    177. qu.push({0, 0, 0});
    178. while(!qu.empty()) {
    179. p = qu.front();
    180. qu.pop();
    181. for(i = 0; i < 6; ++i) {
    182. a = p.x + stepX[i];
    183. b = p.y + stepY[i];
    184. c = p.z + stepZ[i];
    185. if(a < 0 || a >= lenx || b < 0 || b >= leny || c < 0 || c >= lenz) continue;
    186. if(findSpace[a][b][c]) continue;
    187. findSpace[a][b][c] = true;
    188. if(space[a][b][c] == 1 || space[a][b][c] == 1002) {
    189. area += getAreaOne(a, b, c);
    190. }
    191. if(space[a][b][c] % 1000 == 2) {
    192. volume += getVolumeOne(a, b, c);
    193. qu.push({a, b, c});
    194. }
    195. }
    196. }
    197. }
    198. void outputValue() {
    199. int i, j ,k;
    200. for(i = 0; i <= lenx; ++i) {
    201. printf("%d ", axisX[i]);
    202. }
    203. putchar('\n');
    204. for(i = 0; i <= leny; ++i) {
    205. printf("%d ", axisY[i]);
    206. }
    207. putchar('\n');
    208. for(i = 0; i <= lenz; ++i) {
    209. printf("%d ", axisZ[i]);
    210. }
    211. putchar('\n');
    212. for(i = 0; i <= lenx; ++i) {
    213. for(j = 0; j <= leny; ++j) {
    214. for(k = 0; k <= lenz; ++k) {
    215. printf("%d %d %d %d\n", i, j, k, space[i][j][k]);
    216. }
    217. }
    218. }
    219. }
    220. int main() {
    221. int T;
    222. scanf("%d", &T);
    223. while(T--) {
    224. clear();
    225. input();
    226. handleAxis();
    227. handleSpace();
    228. getBorder();
    229. getVolumeAndArea();
    230. volume = MAXN * MAXN * MAXN - volume;
    231. printf("%d %d\n", area, volume);
    232. }
    233. return 0;
    234. }

  • 相关阅读:
    Vector-valued function
    写了一款Jetbrains插件,为了Markdown
    【SpringBoot】SpringBoot怎么接收前端传递过来的数组
    2022春山东大学人工智能导论期末题库附答案
    ansible
    Python爬虫如何设置代理服务器(搭建代理服务器教程)
    PMP_强化练习题(一)180题(附答案及解析)
    CAPL学习之路-DoIP相关函数
    Java后端模拟面试,题集①
    python基于PHP+MySQL的校园帮忙领取快递平台
  • 原文地址:https://blog.csdn.net/qq278672818/article/details/126475749