原题链接
一道有些复杂的模拟题。
核心思路是:先用字符数组储存一个正方体,然后按照从左到右,从下到上,从后向前的顺序一个一个摆上去。
这里有几个问题需要注意:
1.每一块正方体的坐标位置计算
2.第一个正方体的坐标位置
这里规定正方体的坐标是其左上顶点的坐标
对于其他正方体,仔细观察,很容易找到规律:从左向右时正方体行数和左边底部正方体的行数一致,列数加四;从下到上时列数与下方的正方体一致,行数减三。
每行第一个正方体行数与上一行相比要加二,列数满足规律2 * (M - m - 1) - 2,其中M是总行数,m是上一行的行数(从0开始枚举)。如果不理解,可以用代码跑一下m行n列,每个格的正方体数均为1的测试数据,仔细观察就能理解。
而第一个正方体的坐标处理略有些复杂。它的列坐标很容易确定2*M-2,但是行坐标与全局的正方体都有关。它的行坐标要保证最高的正方体行坐标刚好为0。根据这个思路很容易写出代码。
#include<iostream>
#include<climits>
#include<algorithm>
#include<string>
#include<cmath>
using namespace std;
int M, N;
// 记录要输出的行数和列数
int maxH, maxL;
// 储存正方体个数
int p[60][60];
char ans[500][200];
// 一个正方体
char cube[6][8] =
{
{"..+---+"},
{"./ /|"},
{"+---+ |"},
{"| | +"},
{"| |/."},
{"+---+.."}
};
// 在(i,j)坐标处绘制一个正方体,并同时记录最大的行列
void draw(int i, int j) {
for (int ii = i, t = 0; t < 6; ii++, t++) {
for (int jj = j, k = 0; k < 7; jj++, k++) {
if (cube[t][k] != '.') {
ans[ii][jj] = cube[t][k];
maxH = max(maxH, ii);
maxL = max(maxL, jj);
}
}
}
}
int main()
{
ios_base::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin >> M >> N;
// 先全部设为.
for (int i = 0; i < 200; i++) {
for (int j = 0; j < 200; j++) {
ans[i][j] = '.';
}
}
// 记录每行正方体个数最大值
for (int m = 0; m < M; m++) {
for (int n = 0; n < N; n++) {
cin >> p[m][n];
p[m][N] = max(p[m][N], p[m][n]);
}
}
// startx starty 是第一个正方体的位置坐标
// 先让其在第0行满足最高的正方体行数为0
// 然后枚举每一行,不断修改startx的值
int starty = 2 * M - 2, startx = (p[0][N] - 1) * 3;
for (int m = 0; m < M; m++) {
int mx = startx + m * 2 - (p[m][N] - 1) * 3;
if (mx < 0)
startx -= mx;
}
// 绘图 这个不再多讲 自己找找规律吧
for (int m = 0; m < M; m++) {
for (int n = 0; n < N; n++) {
int num = 0;
while (p[m][n]--) {
draw(startx - num * 3, starty);
num++;
}
starty += 4;
}
starty = 2 * (M - m - 1) - 2;
startx += 2;
}
for (int i = 0; i <= maxH; i++) {
for (int j = 0; j <= maxL; j++) {
cout << ans[i][j];
}
cout << endl;
}
return 0;
}