線上OJ:
一本通-1977:【08NOIP普及組】立體圖
核心思想:
本題采用模擬方法一個一個畫小方塊(雖然畫的是立體空間的積木,但本質還是在二維平面上畫圖形)
本題的難點在于:
1、如何確定二維平面畫布的大小(畫布的高 h 對應二維平面的行向量,畫布寬度L對應二維平面的列向量)
2、如何確定每個積木的起點坐標 ( 左下角作為起點)
3、如何處理遮擋
觀察難點1(如下圖):
答:我們發現,畫布的寬度 L = 1 + 4 ? n + 2 ? m L = 1 + 4*n + 2*m L=1+4?n+2?m; 畫布的高度 h = m a x ( h , 1 + 3 ? a [ i ] [ j ] + 2 ? ( m ? i + 1 ) ) h = max(h, 1 + 3 * a[i][j] + 2 * (m-i+1)) h=max(h,1+3?a[i][j]+2?(m?i+1))
觀察難點2(如下圖):
答:我們發現:第 i 行第 j 列的矩形的左下角頂點位于畫板的第 h ? ( m ? i ) ? 2 h - ( m - i ) * 2 h?(m?i)?2 行,第 1 + ( j ? 1 ) ? 4 + ( m ? i ) ? 2 1 +( j - 1 ) * 4 + ( m - i) * 2 1+(j?1)?4+(m?i)?2 列
觀察難點3:
由于前面的遮擋后面的,上面的遮擋下面的,右面的遮擋左面的。所以繪制積木時采用逆向順序:從后往前畫(從第1行到第m行),從左往右畫(從第1列到第n列),從下往上畫(此時只要行索引每次-3即可,如下圖所示)
題解代碼:
#include <iostream>
using namespace std;int m, n, l, h;
int a[101][101]; // a[i][j] 第i行第j列的區域上方疊放積木的數量
char prt[1001][1001]; // 屏幕畫布所對應的二維數組
char box[6][8]=
{"..+---+","./ /|","+---+ |","| | +","| |/.","+---+..",
};void draw(int x, int y)
{for(int i = 0; i < 6; i++)for(int j = 0; j < 7; j++) // 傳進來的行索引需反向;列索引方向一致,不需要變化if(box[i][j] != '.') prt[x-5+i][y+j] = box[i][j]; // 傳進來的x是積木左下角的行索引(第6行),x-1是第5行,x-2是第4行... x-5是第1行
}int main()
{scanf("%d %d", &m, &n);l = 1 + 4*n + 2*m; // 整體圖像在“畫板”水平區域的寬度for(int i = 1; i <= m; i++) // 從后往前讀入 m 行for(int j = 1; j <= n; j++) // 從左往右讀入 n 列{scanf("%d", &a[i][j]);h = max(h, 1 + 3 * a[i][j] + 2 * (m-i+1)); // 整體圖像在“畫板”垂直區域的高度}for(int i = 1; i <= h; i++) // 高度對應數組的行,寬度對應數組的列for(int j = 1; j <= l; j++) prt[i][j] = '.'; // 全初始化為背景的‘.’for(int i = 1; i <= m; i++){for(int j = 1; j <= n; j++){int x, y; // 因為共有m行n列個區域。(x,y) 表示第i行第j列區域的左下角在“畫板”上對應的行索引和列索引x = h - 2 * (m-i);y = 4 * (j-1) + 2 * (m-i) + 1;while(a[i][j]--) // 疊加了幾塊積木,就畫幾次{draw(x, y); // 疊加的積木,每高一層,左下角頂點坐標在畫布上的行索引少3x -= 3;}}}for(int i = 1; i <= h; i++){for(int j = 1;j <= l; j++)printf("%c", prt[i][j]);printf("\n");}return 0;
}