1. 程式人生 > 實用技巧 >P5730 【深基5.例10】顯示屏

P5730 【深基5.例10】顯示屏

https://www.luogu.com.cn/problem/P5730

P5730 【深基5.例10】顯示屏 題解

題目的意思很明確,要我們通過輸入的數字來構建一個顯示屏,使得上面顯示這些數字。

許多題解裡建立了一個三維char陣列來儲存每一個數字,然後進行輸出,其中打表浪費了大量的時間。我想,既然樣例輸出裡就有現成的\(0 \to 9\)每一個數字的形狀,為什麼不直接拿過來用呢?

首先我建立了一個數組base_1來儲存樣例輸出,注意這裡行和列的大小一定要準確,因為字串是以\0結尾的,獨佔一個空間:

char base_1[5][40]={
	"XXX...X.XXX.XXX.X.X.XXX.XXX.XXX.XXX.XXX",
	"X.X...X...X...X.X.X.X...X.....X.X.X.X.X",
	"X.X...X.XXX.XXX.XXX.XXX.XXX...X.XXX.XXX",
	"X.X...X.X.....X...X...X.X.X...X.X.X...X",
	"XXX...X.XXX.XXX...X.XXX.XXX...X.XXX.XXX",
//   0 2 4 6 8 
};

這裡的註釋0 2 4 6 8是什麼意思,之後會提到。

我們將答案儲存在一張畫布(即“顯示屏”)內。now是什麼意思,一會兒也會說。

char pict[6][9999];//畫布,即題目中的"顯示屏"。 
int now=0;//表示這個數字應該在畫布的第幾個位置寫入 

這裡我的想法是,掃描輸入的數字串,然後依次轉化成真實數字。接下來的工作是從base_1中“摳取”需要的數字。根據上面的註釋,我們會發現,數字\(i\)base_1中對應的範圍是(只寫出橫向座標,縱向座標就是\(0 \to 4\)):\([4i,4i+2]\)。依據這個性質,我們就可以“摳取”需要的數字。

那麼怎麼把摳出來的數字寫入到畫布裡呢?這裡now

就派上用場了。now儲存的是下一個數字要在橫向座標的什麼位置輸入畫布。一開始,now=0,然後插入一個數字(比如說\(0\))之後,now就應該移到4的位置。再在這裡插入一個數字1。每次插入一個數字,now就要後移4格。它的作用相當於電腦游標。至於補全一列'.'的時候,我們直接從now-1的位置插入就行。

處理相對位置有點麻煩,詳見註釋。注意陣列的第一維是縱向座標,第二維才是橫向。並且都是從\(0\)開始索引計數的:

void work(string s){
	for(int p=0;p<s.length();p++){
		int num=s[p]-'0';//轉化成真實數字 
		int xst=num*4;//這個數字對應的base_1裡的位置起始點 
		for(int i=0;i<=4;i++){//遍歷這個數字對應的base_1裡的點 
			for(int j=xst;j<=xst+2;j++){
				pict[i][j-xst+now]=base_1[i][j];//j-xst將[xst,xst+2]對映為[0,2],再加上now表示從now位置寫入畫布 
			}
		}
		for(int i=0;i<=4;i++)
			pict[i][now-1]='.';//補全一列空點 
		now+=4;//下一個寫入的位置 
	}
}

輸出就比較簡單了:

void print(){//輸出 
	for(int i=0;i<=4;i++){
		for(int j=0;j<=len*4;j++){//len*4表示預期畫布寬度(其實只要這個數字夠大就行,C++貌似會自動換行) 
			cout<<pict[i][j];//即使輸入的長度與原數字串長度不相等,它竟然也能正常工作! 
		}
		cout<<endl;
	}
}

總體AC程式碼:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
char base_1[5][40]={
	"XXX...X.XXX.XXX.X.X.XXX.XXX.XXX.XXX.XXX",
	"X.X...X...X...X.X.X.X...X.....X.X.X.X.X",
	"X.X...X.XXX.XXX.XXX.XXX.XXX...X.XXX.XXX",
	"X.X...X.X.....X...X...X.X.X...X.X.X...X",
	"XXX...X.XXX.XXX...X.XXX.XXX...X.XXX.XXX",
//   0 2 4 6
};
char pict[6][9999];//畫布,即題目中的"顯示屏"。 
int now=0;//表示這個數字應該在畫布的第幾個位置寫入 
int len;//字串長度
void work(string s){
	for(int p=0;p<s.length();p++){
		int num=s[p]-'0';//轉化成真實數字 
		int xst=num*4;//這個數字對應的base_1裡的位置起始點 
		for(int i=0;i<=4;i++){//遍歷這個數字對應的base_1裡的點 
			for(int j=xst;j<=xst+2;j++){
				pict[i][j-xst+now]=base_1[i][j];//j-xst將[xst,xst+2]對映為[0,2],再加上now表示從now位置寫入畫布 
			}
		}
		for(int i=0;i<=4;i++)
			pict[i][now-1]='.';//補全一列空點 
		now+=4;//下一個寫入的位置 
	}
}
void print(){//輸出 
	for(int i=0;i<=4;i++){
		for(int j=0;j<=len*4;j++){//len*4表示預期畫布寬度(其實只要這個數字夠大就行,C++貌似會自動換行) 
			cout<<pict[i][j];//即使輸入的長度與原數字串長度不相等,它竟然也能正常工作! 
		}
		cout<<endl;
	}
}
int main(){
	cin>>len;
	string str;
	cin>>str;
	work(str);
	print();
	return 0;
}