- 「入门题单7」模拟与高精度
模拟 - 立体图 题解
- 2022-10-4 19:06:21 @
题面
小渊很懒,给你各个位置的高度,让你画立体图。
思路
首先,根据题单名称,我们可以知道要模拟。
1. 首先,当然也是本题最难的点,就是方块之间的前后视觉遮挡问题。
显然,对于斜二测画法的立体图,后面靠左的区域会被前者覆盖。那么我们自然会发现,从前往后画,覆盖问题会变得很复杂(不过也不是不能做)。
所以,我们不妨试试从俯视视角的左上角开始画。
我们以一个方块为一个单位开始画图。这里我们定义一个char二维数组来存储一个方块,并用题给的.
符号来表示空区域。
char[][] one = {
"..+---+".toCharArray(),
"./ /|".toCharArray(),
"+---+ |".toCharArray(),
"| | +".toCharArray(),
"| |/.".toCharArray(),
"+---+..".toCharArray()
};
然后,对于每一个新加入的方块,我们只要对one
进行行列的遍历,如果不为.
,就将前者对应位置覆盖。
2. 其次是定位的问题。
每个方块的大小是6 x 7
,格子的数目也给出了范围,此处我们可以开一个存储数据的容量为500 x 500
的数组(其实是随便输的,可能还不满足最大的容量,只能说测试数据不够全面,反正开大一点就好啦~),那么右下角的点坐标就为(499, 499)
。
好的,那我们先拿几个图来推一下坐标的式子。
此处定义每个格子的坐标为(i, j, h)
注:为了更加形象一点,我就直接定义h
下标从1
开始,而i
和j
仍从0
开始。
对于左下角的高度为1的方块(即坐标为(m - 1, 0, 1)
的方块),他的左上顶点位于(494, 0)
。
对于(m - 2, 1, 1)
的方块,他的左上顶点位于(492, 2)
。
可见对于横纵坐标的改动,会有以2为倍数的改变,在高度为1时,我们可以推出下面的坐标式子:
(494 - 2(m - i - 1), 4j + 2(m - i - 1))
高度变化对坐标的影响是显而易见的。每当高度加1,横坐标会减少3(不能理解的话可以对照一下题面中两个方块上下相邻的图)。因此我们完善一下式子如下:
(497 - 2(m - i - 1) - 3h, 4j + 2(m - i - 1))
然后我们只需从俯视视角的左上角开始循环添加方块就ok了。
3. 输出问题 在每次添加方格的时候,我们可以记录一下上区间和右区间,上区间就是所有左上顶点的纵坐标最小值,右区间就是所有右上顶点横坐标最大值。
ok,解毕。
AC(Java)代码
import java.util.*;
public class Main {
static char[][] one = {
"..+---+".toCharArray(),
"./ /|".toCharArray(),
"+---+ |".toCharArray(),
"| | +".toCharArray(),
"| |/.".toCharArray(),
"+---+..".toCharArray()
};
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
char[][] ans = new char[500][500]; //开数组
for(int i=0;i<500;i++) for(int j=0;j<500;j++) ans[i][j] = '.'; //空位置填上占位符"."
int m = scanner.nextInt(), n = scanner.nextInt();
int[][] height = new int[m][n];
for(int i=0;i<m;i++) for(int j=0;j<n;j++) height[i][j] = scanner.nextInt();
int top = 500, right = 0;
for(int i=0;i<m;i++) for(int j=0;j<n;j++) for(int h=1;h<=height[i][j];h++){
//从左上角画起,存到数组底部,到时候记录最高和最右的位置即可
int startI = 497 - 2 * (m - i - 1) - 3 * h, startJ = 4 * j + 2 * (m - i - 1);
top = Math.min(top, startI);
right = Math.max(right, startJ + 6);
for(int p=0;p<6;p++) for(int q=0;q<7;q++){
if(one[p][q] != '.') ans[startI + p][startJ + q] = one[p][q];
}
}
for(int i=top;i<=499;i++) {
for(int j=0;j<=right;j++) System.out.print(ans[i][j]);
System.out.println();
}
}
}
随手转了一下cpp (update 22.12.12)
AC(cpp)代码
#include <bits/stdc++.h>
using namespace std;
char one[6][8] = {
"..+---+",
"./ /|",
"+---+ |",
"| | +",
"| |/.",
"+---+.."
};
char ans[500][500]; //开数组
int height[52][52];
int main() {
for (int i = 0; i < 500; i++) for (int j = 0; j < 500; j++) ans[i][j] = '.'; //空位置填上占位符"."
int m, n;
scanf("%d %d", &m, &n);
for (int i = 0; i < m; i++) for (int j = 0; j < n; j++) scanf("%d", &height[i][j]);
int top = 500, right = 0;
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
for (int h = 1; h <= height[i][j]; h++) {
//从左上角画起,存到数组底部,到时候记录最高和最右的位置即可
int startI = 497 - 2 * (m - i - 1) - 3 * h, startJ = 4 * j + 2 * (m - i - 1);
top = min(top, startI);
right = max(right, startJ + 6);
for (int p = 0; p < 6; p++)
for (int q = 0; q < 7; q++) {
if (one[p][q] != '.') ans[startI + p][startJ + q] = one[p][q];
}
}
for (int i = top; i <= 499; i++) {
for (int j = 0; j <= right; j++) printf("%c", ans[i][j]);
printf("\n");
}
}