P9456 题解

· · 题解

题目传送门

Easy Version 传送门

感觉这题评黄有些过分,应该是中位橙的难度,但真的很烧脑干

分析

本题难点在于特别特别为复杂的坐标转换。

首先是读入,大致有两种读入方法。第一种是按题面的输入,题面写的是输入的 a_{x,y,z} 表示的是格子 (y,z,x),所以若三重循环的变量分别为 i,j,l,则应该读入 a_{j,l,i};第二种就是直接输入 a_{i,j,l}。其实本质没有什么区别,本篇题解就以第一种输入为例:

int n,m,k;
    cin>>n>>m>>k;
    for(int i=1;i<=k;i++)
    {
        for(int j=1;j<=n;j++)
        {
            for(int l=1;l<=m;l++)
            {
                cin>>a[j][l][i];
            }
        }
    }

然后我们再沿三种视图来讲解:

正视图

正视图要求自上而下自左至右。因此我们首先需要倒序枚举 z 轴(即变量 k,代表长方体的高),其次正序枚举 x 轴(即变量 n,代表长方体的长),最后再是正序往后m 个(即长方体的宽)小正方体即可。在枚举中,输出每一格的情况即可。

正视图部分代码:

for(int i=k;i;i--)
    {
        for(int j=1;j<=n;j++)
        {
            int flag=0;
            for(int l=1;l<=m;l++)
            {
                if(a[j][l][i])
                {
                    flag=1;
                    break;
                }
            }
            cout<<flag<<" ";
        }
        putchar('\n');
    }

左视图

左视图要求自上而下自后至前。因此我们首先需要倒序枚举 z 轴(即变量 k,代表长方体的高),其次倒序枚举 y 轴(即变量 m,代表长方体的宽),最后再是正序往右n 个(即长方体的长)小正方体即可。在枚举中,输出每一格的情况即可。

但是这里还需注意,这里不应该再是 a_{j,l,i} 了,因为循环变量本身就“代表”了其第一次所对应的标准变量,比如 i 对应 k,那么这次它也就“代表” k。所以按此规律,原本变量为 n,m,k,现在对应一下,这里应该为 a_{l,j,i}。(因为在这里 i 代表 kj 代表 ml 代表 n,标准顺序是 n,m,k,所以循环变量应该排序成 l,j,i。)

这个规律通用于三个俯视图。当然,你也可以称其为小技巧。

左视图部分代码:

for(int i=k;i;i--)
    {
        for(int j=m;j;j--)
        {
            int flag=0;
            for(int l=1;l<=n;l++)
            {
                if(a[l][j][i])
                {
                    flag=1;
                    break;
                }
            }
            cout<<flag<<" ";
        }
        putchar('\n');
    }

俯视图

俯视图要求自后至前自左至右。因此我们首先需要倒序枚举 y 轴(即变量 m,代表长方体的宽),其次正序枚举 x 轴(即变量 n,代表长方体的长),最后再是正序往下k 个(即长方体的高)小正方体即可。在枚举中,输出每一格的情况即可。

这里循环变量也需对应,按“左视图”里的方法对应后,此处应为 a_{j,i,l}

俯视图部分代码:

for(int i=m;i;i--)
    {
        for(int j=1;j<=n;j++)
        {
            int flag=0;
            for(int l=1;l<=k;l++)
            {
                if(a[j][i][l])
                {
                    flag=1;
                    break;
                }
            }
            cout<<flag<<" ";
        }
        putchar('\n');
    }

完整代码就不给了,组合一下四段代码就是。

最后再说一个小技巧吧。下次遇到这种题目,各位如果实在不知道或想不出来要不要倒序或怎么将循环变量对应,就可以尝试枚举所有种情况。枚举这 i,j,l,一共也就 2\times3=6 种可能。再加上倒序,一共也就 12 种可能,依次尝试即可。虽然说这有点类似于骗分,但至少可以 AC,赛时我就是这样 AC 的。