← 返回题目页

A0736 [2008J4]立体图

标程

#include <bits/stdc++.h>
using namespace std;

// 立体图:把 m x n 个格子上摞的积木画成字符画
//
// 投影规则(x 向右为列,y 向上为行,画布左下角为原点):
//   · 一块积木的正面宽 4 列、高 3 行(上下两条边 + 两行 '|')
//   · 顶面与右侧面都朝「右上」偏 (2 列, 2 行)
//   · 同一行相邻的格子横向差 4 列;往后再退一排纵向差 (2 列, 2 行)
//
// 画法(画家算法):先画后排再画前排,同一排从左往右,每格从下往上;
// 近的覆盖远的,正好把被挡住的棱盖掉。

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

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

    // 画布大小:最高的那块积木的顶面后沿、最右那格的右侧面后沿
    int H = 0, W = 0;
    for (int i = 1; i <= m; i++) {
        for (int j = 1; j <= n; j++) {
            int by = 2 * (m - i);
            int bx = 4 * (j - 1) + 2 * (m - i);
            H = max(H, by + 3 * a[i][j] + 3);
            W = max(W, bx + 7);
        }
    }
    vector<string> pic(H, string(W, '.'));

    // y 从画布底部往上数
    auto put = [&](int x, int y, char c) {
        if (x < 0 || x >= W || y < 0 || y >= H) return;
        pic[H - 1 - y][x] = c;
    };

    for (int i = 1; i <= m; i++) {          // 从后排画到前排
        for (int j = 1; j <= n; j++) {      // 同一排从左往右
            int bx = 4 * (j - 1) + 2 * (m - i);
            int by = 2 * (m - i);
            for (int k = 0; k < a[i][j]; k++) {   // 每格从下往上
                int y0 = by + 3 * k;

                // 正面:上下两条横边 + 中间两行竖边
                for (int t = 0; t <= 4; t++) {
                    char c = (t == 0 || t == 4) ? '+' : '-';
                    put(bx + t, y0, c);
                    put(bx + t, y0 + 3, c);
                }
                put(bx, y0 + 1, '|');
                put(bx, y0 + 2, '|');
                put(bx + 4, y0 + 1, '|');
                put(bx + 4, y0 + 2, '|');
                // 正面中间要留空(把被挡住的部分盖掉)
                for (int t = 1; t <= 3; t++) {
                    put(bx + t, y0 + 1, ' ');
                    put(bx + t, y0 + 2, ' ');
                }

                // 顶面:两条斜边 + 后沿
                put(bx + 1, y0 + 4, '/');
                put(bx + 5, y0 + 4, '/');
                put(bx + 2, y0 + 4, ' ');
                put(bx + 3, y0 + 4, ' ');
                put(bx + 4, y0 + 4, ' ');
                for (int t = 0; t <= 4; t++) {
                    char c = (t == 0 || t == 4) ? '+' : '-';
                    put(bx + 2 + t, y0 + 5, c);
                }

                // 右侧面:底沿斜线 + 后沿竖边
                put(bx + 5, y0 + 1, '/');
                put(bx + 5, y0 + 2, ' ');
                put(bx + 5, y0 + 3, ' ');
                put(bx + 6, y0 + 2, '+');
                put(bx + 6, y0 + 3, '|');
                put(bx + 6, y0 + 4, '|');
                put(bx + 6, y0 + 5, '+');
            }
        }
    }

    for (const string &row : pic) {
        cout << row << '\n';
    }
    return 0;
}

动画演示