『ACM C++』PTA浙大 | 基礎題 - 打印沙漏


《數據結構》開課前的一些小作業練習,可能因為一個寒假都沒有打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;
 } 

可以發現內存使用量大大減少,將兩塊的上下繪制合並到一塊之后代碼空間復雜度下降很多。

 

注:如果有更好的解法,真心希望您能夠評論留言貼上您的代碼呢~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM