zoukankan      html  css  js  c++  java
  • 堆栈—冲刺十三模拟赛 外星密码

    P1967 - 【NOIP2010冲刺十三模拟赛】外星密码

    Description

    有了防护伞,并不能完全避免2012的灾难。地球防卫小队决定去求助外星种族的帮助。经过很长时间的努力,小队终于收到了外星生命的回信。但是外星人发过来的却是一串密码。只有解开密码,才能知道外星人给的准确回复。 
    解开密码的第一道工序就是解压缩密码,外星人对于连续的若干个相同的子串“x”会压缩为“[DX]”的形式(D是一个整数且0<D≤99),比如说字符串“CBCBCBCB”就压缩为“[4CB]”或者“[2[2CB]]”,类似于后面这种压缩之后再压缩的我们称之为二重压缩。如果是“[2[2[2CB]]]",则是三重。 
    现在我们给你外星人发送的密码,请你对其进行解压缩。

    Input

    1行:一个字符串

    Output

    1行:一个字符串

    Sample Input

    输入样例一: 
    AC[3FUN] 
    输入样例二: 
    [2BILI]

    Sample Output

    输出样例一: 
    ACFUNFUNFUN

    输出样例二: 
    BILIBILI

    Hint

    数据范围: 
    对于50%的数据:解压后的字符串长度在1,000以内,最多只有三重压缩。 
    对于100%的数据:解压后的字符串长度在20,000以内,最多只有十重压缩。 
    保证只包含数字、大写字母、‘[’和‘]’。































    字符串栈维护,一个存数,一个存字符串(就是括号里面的字符串)

    然后每读到'['的时候就读一个数,进栈,然后就读字符,一直读到'[' 或者 ']'的时候停下,并把字符串也压栈。
    后面遇到']'的时候就弹出数栈和字符串栈进行复制加倍,最后输出
    例子 A[2A[2AB]A],很显然应该输出 A | A ABAB A | A ABAB A  (空格和竖线加上便于观察)
    对于案例,需要手动模拟一下入栈出栈的过程......

        

    步骤 数栈 字符串栈
    定义字符串s最为答案用 <null> <null>
    读到A,并且不再括号内,所以加入s,s现在为"A" <null> <null>
    读到'[',然后读一个数2,压栈 2 <null>
    一直读字符串,直到'['或']'停下,结果为A,压栈 2 A
    刚才最后读到的为'[',所以读一个数字2,压栈

    2
    2

    A
    接着又读字符串,读到']'停止,结果为AB,压栈

    2
    2

    AB
    A
    刚才最后读到']',所以弹出数栈和字符串栈进行加倍 2 A
    加倍后变为ABAB,压栈 2

    ABAB
    A

    接着读到字符串A压栈 2

    A
    ABAB
    A

    又读到']',弹出字符串栈和数栈加倍 <null> <null>
    加倍为AABABAAABABA,压栈 <null> AABABAAABABA
    读到文末,字符串栈弹出 <null> <null>
    s加上字符串栈弹出的,输出 <null> <null>

        


















    但是具体操作起来,有一些细节是需要注意的。

    模拟时注意几个地方
    ①:如何判断是否在括号里面呢?我们可以用区间的思想,用一个变量,遇到'['就+1,遇到']'就-1,
    那么当其值为0的时候就不在括号内
    ②:如何弹出,弹出几个呢?注意到第二处和第三处,如果不是手动维护,根本不知道到底要弹出几个,
    那该怎么办呢?一个有效的解决办法就是在数字压栈的时候同时把一个"["(或者其他可以区分的符号)也压入字符
    串栈,那为什么不在字符串入栈的时候压呢?因为字符串入栈的时候不一定是因为'['而入栈的。
    这样处理后,我们每次只需一直弹出字符串栈,直到弹出的是"["为止。
    还有一个需要注意的问题就是弹出的时候,要注意字符串拼接相加的顺序,后出栈的要加在前面(可以自己模拟一次),才能保证不改变原来顺序。

    代码如下

    #include<cstdio>
    #include<stack>
    #include<string>
    #include<iostream>
    using namespace std;
    /*
    	用的栈维护,一个存数,一个存字符串(就是括号里面的字符串)
    	然后每读到'['的时候就读一个数,进栈,然后就读字符,一直读到'[' 或者 ']'的时候停下,并把字符串也压栈。
    	后面遇到']'的时候就弹出数栈和字符串栈进行复制加倍,最后输出
    	例子 A[2A[2AB]A],很显然应该输出 A | A ABAB A | A ABAB A  (空格和竖线加上便于观察)
        对于案例,需要手动模拟一下入栈出栈的过程......(省略)
        模拟时注意几个地方
    	①:如何判断是否在括号里面呢?我们可以用区间的思想,用一个变量,遇到'['就+1,遇到']'就-1,
    		那么当其值为0的时候就不在括号内
    	②:如何弹出,弹出几个呢?注意到第二处和第三处,如果不是手动维护,根本不知道到底要弹出几个,
    		那该怎么办呢?一个有效的解决办法就是在数字压栈的时候同时把一个"["(或者其他可以区分的符号)也压入字符
    		串栈,那为什么不在字符串入栈的时候压呢?因为字符串入栈的时候不一定是因为'['而入栈的。
    		这样处理后,我们每次只需一直弹出字符串栈,直到弹出的是"["为止。
    
    	还有一个需要注意的问题就是弹出的时候,要注意字符串拼接相加的顺序,后出栈的要加在前面(可以自己模拟一次),
    	才能保证不改变原来顺序
    */
    string s;           //s保存解压串的结果
    stack<int> nu;      //数字栈
    stack<string> alp;  //字符串栈
    int co=0;
    
    void work()
    {
    	char ch;
    	int x;
    	while(scanf("%c",&ch)==1)
    	{
    		if(ch=='
    ') break;//只读第一行
    		if(co>0)
    		{
    			string ss="";  //储存[]之间的连续子串
    			while(ch!=']' && ch!='[')
    			{
    				ss+=ch;
    				scanf("%c",&ch);
    			}
    			alp.push(ss); //[]之间的子串,压入栈
    		}
    
    		if(ch=='[')
    		{
    			co++;
    			scanf("%d",&x);
    			nu.push(x);
    			alp.push("[");
    		}
    
    		if(ch==']')     //遇到 ] 解压串栈进行拓展,并将拓展后的串压入字符串栈
    		{
    			co--;
    			x=nu.top();
    			nu.pop();
    			string t="";
    			while(!alp.empty())   // 查找哪些串位于当前的 ] 范围内,(直到字符串栈中遇到第一个 '[' 为止)
    			{
    				string ss=alp.top();
    				alp.pop();
    				if(ss=="[") break;
    				t=ss+t;
    			}
    			string tt=t;
    			t="";
    			for(int i=1; i<=x; i++) t=t+tt;   //循环赋值,解压操作
    			alp.push(t);                      //解压后子串入栈
    		}
    		if(co<=0)                             //如果co计数为0了,说明栈里没有元素在[]中了,子串出栈加到s前面
    			while(!alp.empty())               //注意这个地方只有当co为0,立即将栈底的子串出栈加到结果s中
    			{                       //才能保证栈底先入栈的前段部分子串先输出,否则会后进栈的先出(出现倒转了)
    				if(alp.top()!="[") s+=alp.top();
    				alp.pop();
    			}
    		if(ch!='[' && ch!=']') s+=ch;  //中间不属于任何[]部分的字符直接粘贴到解压结果串s的后面
    	//	cout<<s<<endl;
    	}
    	cout<<s;
    	/*                     // 检验,在经过压栈,出栈的字符密码解压操作后,字符串栈是否为空
    	while(!alp.empty())    // 如果在上边部分边输入边进行压栈、出栈处理后,栈中还剩余子串元素,出栈输出
    	{                      // 事实上只要是一个合法的密码串,经过入栈,出栈的解压操作后,最终栈必定为空了
    		cout<<alp.top();
    		alp.pop();
    	}
    	*/
    	printf("
    ");
    }
    
    int main()
    {
    	work();
    	return 0;
    }

  • 相关阅读:
    137. 只出现一次的数字 II
    JS_利用Canvas进行图片旋转
    JS_图片压缩并预览
    计蒜客——等和的分隔子集
    中缀表达式转后缀并计算(只考虑个位整数,不考虑除0等情况)
    求最小数 * 区间和最大值
    967 质量检测
    PAT-1102(Invert a Binary Tree)
    PAT-1100(Mars Numbers)
    PAT-1099(Build A Binary Search Tree)
  • 原文地址:https://www.cnblogs.com/tham/p/6827159.html
Copyright © 2011-2022 走看看