1. 程式人生 > 其它 >P1928 外星密碼 遞迴/模擬

P1928 外星密碼 遞迴/模擬

題目描述

有了防護傘,並不能完全避免 2012 的災難。地球防衛小隊決定去求助外星種族的幫 助。經過很長時間的努力,小隊終於收到了外星生命的回信。但是外星人發過來的卻是一 串密碼。只有解開密碼,才能知道外星人給的準確回覆。解開密碼的第一道工序就是解壓 縮密碼,外星人對於連續的若干個相同的子串“X”會壓縮為“[DX]”的形式(D 是一個整 數且 1≤D≤99),比如說字串“CBCBCBCB”就壓縮為“[4CB]”或者“[2[2CB]]”,類 似於後面這種壓縮之後再壓縮的稱為二重壓縮。如果是“[2[2[2CB]]]”則是三重的。現 在我們給你外星人傳送的密碼,請你對其進行解壓縮。

輸入格式

第一行:一個字串

輸出格式

第一行:一個字串

輸入輸出樣例

輸入 #1
AC[3FUN]
輸出 #1
ACFUNFUNFUN

說明/提示

【資料範圍】

對於 50%的資料:解壓後的字串長度在 1000 以內,最多隻有三重壓縮。

對於 100%的資料:解壓後的字串長度在 20000 以內,最多隻有十重壓縮。 對於 100%的資料:保證只包含數字、大寫字母、’[‘和’]‘

看到這題的第一反應就是,這不是一道大模擬嘛

大概思路是先將整個字串先讀入STR[]之中,然後將其分成兩部分,[]裡面的部分和[]外面的部分,對於[]裡面的部分用string類裡的find()函式去找[和],然後從內層開始一層一層拆出來

一開始是用迴圈去做,非常非常麻煩,程式碼不貼了,看得人直噁心

後來想到這是一道遞迴題目,於是對上述思路進行優化

我們挑選一段[]中的內容來分析

核心程式碼:now=s.find('[',now);

now表示的是當前[的位置,上述遞迴的邊界條件是(now<s.find(']',r)),這個r就是是第一個now

這樣的遞迴之後我們就能找到最裡面的[],然後開始拆包

我們從頭開始走一遍

我們在遞迴內部定義三個變數,int n string s,str

n表示重複次數,s表示當前[]內的最終的答案字串(也就是拆完包之後的結果),str表示當前[]的內部第一個[]拆包出來的結果

首先讀取重複次數,令ans=1,從當前[]的左端點[一路向右端點]掃描,讀入一位(>='0'&&<='9')的字元就將ans乘10並加上當前數字

然後立刻(就是在讀取完次數的下一行、)開始遞迴呼叫,去找下一個[]部分,並將其結果存在str當中,遇到了邊界條件之後返回一個空字元

now=s.find('[',now);

str=solve(now);

邊界條件:(now<STR.find(']',r))

這樣一層層下來我們就會找到最裡面的[]部分,讀取完重複次數後繼續掃描,遇到一個非]的字元就把其拼接在s後面,

s+=STR[i];

直到遇到]為止,此時我們已經獲得了需要重複的字串s,然後將其重複ans次後返回

string s1=“”;

while(ans--)s1+=s;

return s1;

此時我們回到了上一層的

str=solve(now);

順便更新一下當前層的]的位置,儲存在r中

r=STR.find(']',r);

下一層[]中拆包後的結果已經儲存在str中了,我們還是繼續掃描,遇到一個非[的字元就把它拼接在s後面(此時的s已經是這一層[]中的s),遇到[的時候就把str直接拼接在當前s的後面,然後找到與其對應的],從]之後繼續從STR[]中讀取字元,直到遇到這一層的](也就是走到r的位置),然後重複以上步驟,將這一層的s重複這一層的重複次數之後返回,並儲存在上一層的str中,然後逐層遞歸回去,最後的s裡面儲存的就是徹底拆完包之後的字串

到這裡最複雜的[]內的拆包部分就寫完了,剩下的[]之外的部分就不多說了,沒難度了已經

然後我在看題解的時候發現了更好的做法,思路和我上面說的一樣,但是人家是邊讀入邊完成的工作,也就是說,省去了用find()一個個查詢[]區間並且反覆更新now和r這些繁瑣的步驟,這裡就貼別人的優秀程式碼了,我自己那個奇醜無比的就不拿出來獻醜了

#include<bits/stdc++.h>
using namespace std;
string read()
{
    int n;
    string s="",s1;
    char c;
    while (cin>>c)//一直讀入字元,直到Ctrl+z
    {
        if (c=='[')
        {
            cin>>n;//讀入D
            s1=read();//讀入X
            while (n--) s+=s1;//重複D次X
            //注:上面不能寫成while (n--) s+=read();
        }
        else 
        {
            if (c==']') return s;//返回X
            else s+=c;//如果不是'['和']',那就是X的一個字元,所以加進X
        }
    }
}
int main()//巨短主函式
{
    cout<<read(); 
    return 0;
}
此程式碼來自a1_1