《數據結構》開課前的一些小作業練習,可能因為一個寒假都沒有打C++手生了,整個寒假都在幫拍電影做后期特效,導致這道題居然用了兩個鍾去AC,深感慚愧,作個標記吧,下面上題。
一首好曲推薦:同時我也設置成了我的博客背景音樂
《開啟新征程》 —— 流浪地球電影的片尾曲
收藏鏈接:https://music.163.com/#/song?id=1343461538
------------------------------------------------題目----------------------------------------------------------
本題要求你寫個程序把給定的符號打印成沙漏的形狀。例如給定17個“*”,要求按下列格式打印
*****
***
*
***
*****
所謂“沙漏形狀”,是指每行輸出奇數個符號;各行符號中心對齊;相鄰兩行符號數差2;符號數先從大到小順序遞減到1,再從小到大順序遞增;首尾符號數相等。
給定任意N個符號,不一定能正好組成一個沙漏。要求打印出的沙漏能用掉盡可能多的符號。
輸入格式:
輸入在一行給出1個正整數N(≤1000)和一個符號,中間以空格分隔。
輸出格式:
首先打印出由給定符號組成的最大的沙漏形狀,最后在一行中輸出剩下沒用掉的符號數。
輸入樣例:
19 *
輸出樣例:
*****
***
*
***
*****
2
------------------------------------------------題目----------------------------------------------------------
(一) 題目分析:
首先經過題目分析,可知特殊符號數跟行數有着某種特殊關系,除去中間的一顆星星*,可以發現上半部分的是個遞增的等差數列:3,5,7,9,.......,可得通項公式2n+1(其中n = 上半部分行數 = 下半部分行數)
那么求和即為Sn = n2+2n,這是上半部分的。那么上下兩部分即可得到:
總**用量:2( n2+2n) = 2n2+4n
到這里我們就可以算出輸入的數能生成幾行了。
(二)代碼分塊:
首先,先計算得出能上下部分各能生成幾行:
for(i = 1;;i++) { temp = 2*i*i+4*i; if(temp > cNumber-1) break; Max = temp; }
temp臨時存放下一行所需的總量,如果這個總量超過了輸入的量數,那么就break打破永真循環,不把temp值賦值給Max行數,否則就把temp的行數賦值給Max變量。
第二步,繪制上半部分:
for(temp = i-1;temp>0;temp--) { for(int count = 0;count != (i-1)-temp;count++) printf(" "); for(int count = 0;count<(2*temp+1);count++) printf("%c",symbol); printf("\n"); }
這時候的temp就是行數了,i-1是因為永真循環的時候被i++多了一次,所以需要減掉,以樣例為例,輸入19后,此時temp應該為2,也就是給上半部分繪制兩行。
因為題目要求中心對齊,我們同時也發現空格和行數之間的關系,例如第一行是沒有空格的,第二行有一個空格,第三行有兩個空格,所以通過空格數和行的關系去輸出即可,然后每一行最后都換行,代碼就形成了。
第三步,繪制下半部分:
for(temp = 0;temp<=i-1;temp++) { for(int count = 0;count != (i-1)-temp;count++) printf(" "); for(int count = 0;count<(2*temp+1);count++) printf("%c",symbol); printf("\n"); }
此時需要注意,最外層的for,在繪制上半部分的時候,是temp>0,是不取邊界的,如果取了邊界會使上部分多畫一行單個*。我這里選擇的是下半部分取繪制這單個*,因此需要temp<=i-1,取到邊界。
(三)AC代碼:
#include<iostream> #include<stdio.h> using namespace std; int cNumber,Max,i,temp; char symbol; int main() { scanf("%d %c",&cNumber,&symbol); for(i = 1;;i++) { temp = 2*i*i+4*i; if(temp > cNumber-1) break; Max = temp; } for(temp = i-1;temp>0;temp--) { for(int count = 0;count != (i-1)-temp;count++) printf(" "); for(int count = 0;count<(2*temp+1);count++) printf("%c",symbol); if(temp != 0) printf("\n"); } for(temp = 0;temp<=i-1;temp++) { for(int count = 0;count != (i-1)-temp;count++) printf(" "); for(int count = 0;count<(2*temp+1);count++) printf("%c",symbol); printf("\n"); } printf("%d",cNumber-Max-1); return 0; }
(四)AC截圖:
(五)解后分析
題目難度不大,剛開始可能手生,在寫for的時候總是渲染多一行或者找錯最大行數。
推薦知識:
1、將聲明變量放在main主函數外,可以申明稍微大型一點的變量,因為main的函數棧容量有限。同時還有一個好處,在函數外申明數組的時候會自動默認全為0清零。
2、推薦使用scanf("%d %c",&cNumber,&symbol); printf("%c",symbol); 這種C語言輸入輸出方式,在ACM中將能大大減少輸入輸出所占用的算法時間。
(六)優質解法更新:
這是在寫博客的時候突然想到可以從上到下一次性繪圖,寫完博客就去試了一下,還真的可以,空間復雜度大大降低了,同樣也AC,現在貼上代碼:
#include<iostream> #include<cmath> #include<stdio.h> using namespace std; int cNumber,Max,i,temp; char symbol; int main() { scanf("%d %c",&cNumber,&symbol); for(i = 1;;i++) { temp = 2*i*i+4*i; if(temp > cNumber-1) break; Max = temp; } for(temp = 2*(i-1);temp>=0;temp--) { for(int count = i-1;count != abs((i-1)-temp);count--) printf(" "); for(int count = 0;count<2*abs(temp-i+1) + 1;count++) printf("%c",symbol); printf("\n"); } printf("%d",cNumber-Max-1); return 0; }
可以發現內存使用量大大減少,將兩塊的上下繪制合並到一塊之后代碼空間復雜度下降很多。
注:如果有更好的解法,真心希望您能夠評論留言貼上您的代碼呢~