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代码

#include<stdio.h>
#include<string.h>
#include<map>
#include<queue>
using namespace std;#define MAXN 505
#define MAXM 105const int stepX[6] = {1,-1,0,0,0,0};
const int stepY[6] = {0,0,1,-1,0,0};
const int stepZ[6] = {0,0,0,0,1,-1}; struct Box {int x0, y0, z0;int x, y, z;
};struct Point {int x, y, z;
}; Box arrBox[55];
int boxlen;int axisX[MAXM];
int axisY[MAXM];
int axisZ[MAXM];
int lenx, leny, lenz;int space[MAXM][MAXM][MAXM];
bool findSpace[MAXM][MAXM][MAXM];
int volume, area;void clear() {memset(arrBox, 0, sizeof(arrBox));boxlen = 0;memset(axisX, 0, sizeof(axisX));memset(axisY, 0, sizeof(axisY));memset(axisZ, 0, sizeof(axisZ));lenx = 0;leny = 0;lenz = 0;memset(space, 0, sizeof(space));volume = 0;area= 0; memset(findSpace, 0, sizeof(findSpace));
}void input() {int i;Box b;scanf("%d", &boxlen);for(i = 0; i < boxlen; ++i) {scanf("%d %d %d %d %d %d", &b.x0, &b.y0, &b.z0, &b.x, &b.y, &b.z);b.x += b.x0;b.y += b.y0;b.z += b.z0;arrBox[i] = b;}
}void handleAxis() {map<int, int> mpx, mpy, mpz;int i, j;for(i = 0; i < boxlen; ++i) {mpx[arrBox[i].x0] = 1;mpx[arrBox[i].x] = 1;mpy[arrBox[i].y0] = 1;mpy[arrBox[i].y] = 1;mpz[arrBox[i].z0] = 1;mpz[arrBox[i].z] = 1;}i = 1;for(auto ip = mpx.begin(); ip != mpx.end(); ++ip, ++i) {mpx[ip->first] = i;axisX[i] = ip->first;}lenx = i;axisX[lenx] = MAXN;axisX[lenx + 1] = MAXN;i = 1;for(auto ip = mpy.begin(); ip != mpy.end(); ++ip, ++i) {mpy[ip->first] = i;axisY[i] = ip->first;}leny = i;axisY[leny] = MAXN; axisY[leny + 1] = MAXN;i = 1;for(auto ip = mpz.begin(); ip != mpz.end(); ++ip, ++i) {mpz[ip->first] = i;axisZ[i] = ip->first;}lenz = i;axisZ[lenz] = MAXN;axisZ[lenz + 1] = MAXN;for(i = 0; i < boxlen; ++i) {arrBox[i].x0 = mpx[arrBox[i].x0];arrBox[i].x = mpx[arrBox[i].x];arrBox[i].y0 = mpy[arrBox[i].y0];arrBox[i].y = mpy[arrBox[i].y];arrBox[i].z0 = mpz[arrBox[i].z0];arrBox[i].z = mpz[arrBox[i].z];}
}bool isEdge(int a) {return a / 1000 == 1;
} void handleSpace() {int i, j, k, a;for(a = 0; a < boxlen; ++a) {for(i = arrBox[a].x0; i <= arrBox[a].x; ++i) {for(j = arrBox[a].y0; j <= arrBox[a].y; ++j) {for(k = arrBox[a].z0; k <= arrBox[a].z; ++k) {if(i == arrBox[a].x || j == arrBox[a].y || k == arrBox[a].z) {if(space[i][j][k] != 1) {space[i][j][k] = 1001;continue;}}space[i][j][k] = 1;}}}}
}void getBorder() {Point p;int i, a, b, c;queue<Point> qu;space[0][0][0] = 2;qu.push({0, 0, 0});while(!qu.empty()) {p = qu.front();qu.pop();for(i = 0; i < 6; ++i) {a = p.x + stepX[i];b = p.y + stepY[i];c = p.z + stepZ[i];if(a < 0 || a > lenx || b < 0 || b > leny || c < 0 || c > lenz) continue;if(space[a][b][c] % 1000 == 2) continue;if(space[a][b][c] == 0) space[a][b][c] = 2;if(isEdge(space[a][b][c])) space[a][b][c] = 1002;if(space[a][b][c] % 1000 == 2)qu.push({a, b, c}); }}
}int getVolumeOne(int a, int b, int c) {return (axisX[a+1] - axisX[a]) * (axisY[b+1] - axisY[b]) * (axisZ[c+1] - axisZ[c]);
}int getAreaOne(int a, int b, int c) {int sum = 0;if(isEdge(space[a][b][c])) {if(space[a-1][b][c] == 1) {sum += (axisY[b+1] - axisY[b]) * (axisZ[c+1] - axisZ[c]);}if(space[a][b-1][c] == 1) {sum += (axisX[a+1] - axisX[a]) * (axisZ[c+1] - axisZ[c]);}if(space[a][b][c-1] == 1) {sum += (axisX[a+1] - axisX[a]) * (axisY[b+1] - axisY[b]);}}if(space[a][b][c] == 1) {if(space[a-1][b][c] % 1000 == 2) {sum += (axisY[b+1] - axisY[b]) * (axisZ[c+1] - axisZ[c]);}if(space[a][b-1][c] % 1000 == 2) {sum += (axisX[a+1] - axisX[a]) * (axisZ[c+1] - axisZ[c]);}if(space[a][b][c-1] % 1000 == 2) {sum += (axisX[a+1] - axisX[a]) * (axisY[b+1] - axisY[b]);}}return sum;
}void getVolumeAndArea() {volume = 0;area = 0;Point p;int i, a, b, c;queue<Point> qu;findSpace[0][0][0] = true;volume += getVolumeOne(0, 0, 0);qu.push({0, 0, 0});while(!qu.empty()) {p = qu.front();qu.pop();for(i = 0; i < 6; ++i) {a = p.x + stepX[i];b = p.y + stepY[i];c = p.z + stepZ[i];if(a < 0 || a >= lenx || b < 0 || b >= leny || c < 0 || c >= lenz) continue;if(findSpace[a][b][c]) continue;findSpace[a][b][c] = true;if(space[a][b][c] == 1 || space[a][b][c] == 1002) {area += getAreaOne(a, b, c);}if(space[a][b][c] % 1000 == 2) {volume += getVolumeOne(a, b, c);qu.push({a, b, c});}}}
}void outputValue() {int i, j ,k;for(i = 0; i <= lenx; ++i) {printf("%d ", axisX[i]);}putchar('\n');for(i = 0; i <= leny; ++i) {printf("%d ", axisY[i]);}putchar('\n');for(i = 0; i <= lenz; ++i) {printf("%d ", axisZ[i]);}putchar('\n');for(i = 0; i <= lenx; ++i) {for(j = 0; j <= leny; ++j) {for(k = 0; k <= lenz; ++k) {printf("%d %d %d %d\n", i, j, k, space[i][j][k]);}}}
}int main() {int T;scanf("%d", &T);while(T--) {clear();input();handleAxis();handleSpace(); getBorder();getVolumeAndArea();volume = MAXN * MAXN * MAXN - volume;printf("%d %d\n", area, volume);}return 0;
}

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

  1. UVA-1598 交易所 题解答案代码 算法竞赛入门经典第二版

    GitHub - jzplp/aoapc-UVA-Answer: 算法竞赛入门经典 例题和习题答案 刘汝佳 第二版 AC代码 有意思的一个题目.书上说这是一个不错的优先队列练习题,但实际上它其实是一个 ...

  2. UVA-814 邮件传输代理的交互 题解答案代码 算法竞赛入门经典第二版

    GitHub - jzplp/aoapc-UVA-Answer: 算法竞赛入门经典 例题和习题答案 刘汝佳 第二版 AC代码 #include<iostream> #include< ...

  3. UVA-508 莫尔斯电码 题解答案代码 算法竞赛入门经典第二版

    https://github.com/jzplp/aoapc-UVA-Answer 这个题目就是在考验英语水平呀!(或者题目本身也写的不清楚) 尤其是多个完全匹配(!)和模糊匹配(?)的情况,我题意看 ...

  4. UVA-12412 师兄帮帮忙 题解答案代码 算法竞赛入门经典第二版

    https://github.com/jzplp/aoapc-UVA-Answer 好麻烦的一道题. 题目没说如果在选菜单,query和stat的时候输入的时候如果是错误的怎么办,根据测试知道是重新输 ...

  5. 算法竞赛入门经典第二版课后习题答案第二章

    算法竞赛入门经典第二版课后习题答案 第二章 习题2-1水仙花数 输出100-999中的所有水仙花数.若三位数ABC满足ABC=A^3+B^3+C^3,则称其为水仙花数.例如153=1^3+5^3+3^ ...

  6. 补学图论算法:算法竞赛入门经典(第二版)第十一章:

    补学图论算法:算法竞赛入门经典(第二版)第十一章: 倒排索引还没有实现! 下面是左神的图论算法,并查集笔记.和一个美团题目. ''' https://www.nowcoder.com/live/11? ...

  7. 算法竞赛入门经典(第二版)-刘汝佳-第六章 数据结构基础 习题(12/14)

    文章目录 说明 习题 习6-1 UVA 673 平衡的括号 习6-2 UVA 712 S - 树 习6-3 UVA 536 二叉树重建 习6-4 UVA 439 骑士的移动 习6-5 UVA 1600 ...

  8. 算法竞赛入门经典第二版:循环结构程序设计实例与习题

    实例: 1.阶乘之和 输入n,计算S= 1!+2!+3!+-+n!的末六位. 分析:两个循环,里面循环用于计算不同数的阶乘,外面一个循环用于将所有阶乘相加,核心算法 "for(int i=1 ...

  9. 算法竞赛入门经典(第二版) | 程序3-6 WERTYU (UVa 10082)(常量数组)

    题目描述: 输入一个按键盘顺序,向后错一位后敲出的字符串,输出本来想打出的句子, 且输入中不会出现不合法的字符,例如A. Simple input: O S, GOME YPFSU/ Simple o ...

最新文章

  1. 如何在一家内容公司,从零搭建起一支技术团队
  2. Android 中的 Service 全面总结(转)
  3. 2.7 HBase架构深入剖析
  4. 智能机浏览器版本信息获取
  5. SAP WebIDE里UI5应用的隐藏文件project.json
  6. Oracle/PLSQL AFTER DELETE Trigger
  7. sql通用防注入程序php,sql通用防注入系统_PHP教程
  8. JavaScript学习总结(4)——JavaScript数组
  9. Eclipse--java.lang.OutOfMemoryError: PermGen space
  10. 微信小程序之 ----API接口
  11. python的输入输出语句_Python基本输出语句/输入语句/变量解析
  12. 【雷达通信】基于matlab雷达前视成像仿真【含Matlab源码 643期】
  13. python中socket.gaierr errno1104_“socket.gaierror:[Errno 11004]getaddrinfo失败”
  14. 2021年高处安装、维护、拆除复审考试及高处安装、维护、拆除模拟考试题
  15. 转载 CSDN 谈谈我对证券公司一些部门的理解(前、中、后台)
  16. audacity音轨加伴奏_如何在Audacity中使用Crossfade进行音轨之间的无缝过渡
  17. Otsu算法原理与python实现
  18. 外卖行业现状分析_2020餐饮外卖行业市场前景及现状分析
  19. AT指令判断NBIoT网络质量
  20. 已登陆windows忘记密码的修改密码方法重置密码

热门文章

  1. PHP foreach循环语句
  2. 浅谈MySQL连接查询与外键
  3. 【公共管理】mpa硕士研究生论文深度如何提高?有技巧的!
  4. Android软件脱壳分析,使用FRIDA为Android应用进行脱壳的操作指南
  5. swift 常用动画
  6. 365天英语口语学习_12,花销
  7. 2023年电子竞技行业报告
  8. 基于基于模型设计(MBD)(我没打错)的机械臂开发课程学习笔记(1)——基本知识和环境配置
  9. windows显示缩略图(重建缩略图)
  10. QT5.9学习笔记之——程序启动画面