例题1.6 立方体成像 UVa1030

来源:互联网 发布:疯狂联盟狼升级数据 编辑:程序博客网 时间:2024/05/22 07:56

1.题目描述:点击打开链接

2.解题思路:本题只给了六个视图,要求找最大的立方块数,看上去貌似很棘手的一个问题。我们可以尝试用排除法,如果删到不能删除时,那么剩下的立方块自然就是最多的。由于视图中为‘.'的地方一定可以看穿,因此可以把这些能看穿的位置的立方体先去掉。接下来,题目还已知了一个小立方块的六个面都是同色的,如果发现某个立方体存在两个面不同色,那么说明该位置的立方块肯定不存在。把该位置的立方块删除之后,会暴露出新的表面,是它相邻的立方块的表面。假设其中一个相邻的立方体在第二轮检查中发现了存在两个面的颜色不同的状况,说明它也不存在,以此类推,直到某一轮检查中不再存在这样的矛盾时,剩下的立方块就是最多的,当然也是最重的时候。

由此,根据上面的思路,我们可以用一个get函数寻找第k张视图的位置(i,j)处看下去,高度为len的那个位置的三维坐标,这样便于后期的处理。主函数中可以先初始化一个完完整整的立方体,而且每个立方块都没有被涂过色。第一步,先删除肯定不存在的立方体;第二步,开始若干轮的检查,看是否有矛盾面出现。如果第一次遇到时该位置的立方体还未涂过色,那就先涂上此时的颜色;若该位置的立方体已经涂过色且和当前枚举的视图位置的颜色吻合,那么跳过;若不一致,就找到了矛盾面,删除该位置的立方块,并标记本轮检查失败。如果在某一轮检查中没有矛盾面了,说明本轮检查成功,退出循环。最后统计剩下的立方块数目,就是最终的答案。

本题的get函数对于空间想象能力要求比较高,可以画图来进行分析。本题是一道很好的锻炼空间思维的模拟题。

3.代码:

#define _CRT_SECURE_NO_WARNINGS #include<iostream>#include<algorithm>#include<string>#include<sstream>#include<set>#include<vector>#include<stack>#include<map>#include<queue>#include<deque>#include<cstdlib>#include<cstdio>#include<cstring>#include<cmath>#include<ctime>#include<functional>using namespace std;#define REP(i,n) for(int i=0;i<(n);i++)const int N = 10;int n;char pos[N][N][N];char view[6][N][N];char read_char(){char ch;for (;;){ch = getchar();if ((ch >= 'A'&&ch <= 'Z') || ch == '.')return ch;}}void get(int k, int i, int j, int len, int&x, int&y, int&z)//获取在第k个视图中,位置在(i,j)高度为len的那个位置的三维坐标{if (k == 0){ x = len; y = j; z = i; }if (k == 1){ x = n - 1 - j; y = len; z = i; }if (k == 2){ x = n - 1 - len; y = n - 1 - j; z = i; }if (k == 3){ x = j; y = n - 1 - len; z = i; }if (k == 4){ x = n - 1 - i; y = j; z = len; }if (k == 5){ x = i; y = j; z = n - 1 - len; }}int main(){//freopen("t.txt", "r", stdin);while (scanf("%d", &n) == 1 && n){REP(i, n)REP(k, 6)REP(j, n)view[k][i][j] = read_char();REP(i, n)REP(j, n)REP(k, n)pos[i][j][k] = '#';//事先都初始化为完整的立方体,且没有涂色REP(k, 6)REP(i, n)REP(j, n)if (view[k][i][j] == '.')//如果在第k张视图的位置(i,j)能够看穿,那么删掉相应的立方体REP(p, n)//枚举高度p{int x, y, z;get(k, i, j, p, x, y, z);pos[x][y][z] = '.';//删掉对应位置的立方体}for (;;)//进行若干轮尝试,来看看是否还有矛盾的立方块{bool done = true;//确定是否成功REP(k, 6)REP(i, n)REP(j, n)if (view[k][i][j] != '.')//说明有在第k张视图的位置(i,j)立方块,那么枚举高度来确定它的位置{REP(p, n){int x, y, z;get(k, i, j, p, x, y, z);if (pos[x][y][z] == '.')continue;//此位置没有,跳过if (pos[x][y][z] == '#')//此位置存在立方块{pos[x][y][z] = view[k][i][j];//涂成第k张视图,位置(i,j)对应的颜色break;}if (pos[x][y][z] == view[k][i][j])break;//如果此位置的颜色和第k张视图的位置(i,j)处的颜色相同,停止枚举深度pos[x][y][z] = '.';//该位置已经涂过色且颜色不相同,说明该位置不存在立方块,删掉该位置的立方块done = false;//本轮尝试失败}}if (done)break;//本轮尝试成功,退出}int ans = 0;REP(i, n)REP(j, n)REP(k,n)if (pos[i][j][k] != '.')ans++;printf("Maximum weight: %d gram(s)\n", ans);}return 0;}

0 0
原创粉丝点击