ZOJ3829 (后缀表达式)详解,适合新手

题目放在最后面:

 

我想说,这个题对于不知道后缀表达式的人真的坑,看了半天题目结果还迷迷糊糊,但是这个却是铜牌的题目,哎。

非常建议看一看相关博客,关于他们的定义,推荐一篇写的很好的博客:

https://www.cnblogs.com/chensongxian/p/7059802.html

 

看完之后,解这个题就是分分钟的事了,对于一个后缀表达式,我们的求法是:

从左至右扫描表达式,遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(次顶元素 op 栈顶元素),并将结果入栈;重复上述过程直到表达式最右端,最后运算得出的值即为表达式的结果。

那么,当栈中有两个以上数时,遇到运算符就问题不大,但是没那么多数时就要进行处理了。

 

具体操作是:

首先我们算出有多少个数(0-9),我们记为digitnum,多少个*号,我们记为starnum,如果数字少于 *个数+1,那么我们一开始就要插入了。

所以说,我们插入只在最开始,一开始插入starnum + 1 - digitnum个,因为进行n次乘法最少也需要n+1个数。

然后交换呢?

如果在整个字符串中,starnum 和 digitnum的关系合理,那么我们一定可以重排字符串,使其合理,这里我们贪心一下,

如果左边全部是数字,右边全是*,那么他们一定符合条件,比如  666**,所以我们swap操作都努力的变成这样。

注意,是可以任意交换,我开始以为是相邻交换,哎。

那么我们就开始模拟计算这个表达式。

直接for循环,然后if判断

如果栈中元素小于2,但是遇到一个*,(说明不能进行操作),那么把这个*交换到后面去。

如果遇到*,但是栈中元素够,那么栈元素个数减1,因为进行一次操作需要消耗两个元素,得到一个元素。

遇到一个数,就栈的size++;

最后输出ans就可以了。

 

总结一下算法步骤:

首先在开头填充数字(如果需要的话),这就是进行了插入操作。

for循环遍历,if判断

①如果是*号,分两种

1.元素个数够操作,那么个数减1

2.元素个数不够操作,那么把*换到后面,ans++。

②如果是数字,元素个数++。

 

还有一个问题,题目不够严谨

如果结尾不是*,那么应该加1个*的,但是题目的数据没考虑到,这个漏洞大家就不用太在意了。

AC代码:

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<queue>
#include<cstring>
#include<algorithm>
#include<set>
#include<string>
#include<map>
#include<cmath>
#include<vector>
#include<time.h>
#define fori(l,r) for( int i = l ; i <= r ; i++ )
#define forj(l,r) for( int j = l ; j <= r ; j++ )
#define fork(l,r) for( int k = l ; k <= r ; k++ )
#define mem(a,val) memset(a,val,sizeof a)
#define lef rt<<1
#define rig rt<<1|1
#define mid (l+r)>>1
#define inf 0x3f3f3f3f
#define llinf 0x3f3f3f3f3f3f3f3f
#define eps 1e-7
using namespace std;
typedef long long ll;
char s[1006];
int len;
int main()
{
    int T;
    while( scanf("%d",&T)==1 )
    {
        while( T-- )
        {

            scanf("%s",s);
            len = strlen(s);
            int digitnum = 0,starnum = 0;
            for( int i = 0 ; i < len ; i++ )
                if( s[i] == '*' )
                    starnum++;
                else digitnum++;
            int ans = 0,val = 0;
            if( digitnum < starnum+1 )
            {
                ans = starnum+1-digitnum;   //需要插入ans个数
                val = ans;
            }
            int last = len-1;
            for( int i = 0 ; i < len ; i++ )
            {
                if( s[i] == '*' )
                {
                    if( val < 2 )
                    {
                        while( last >= 0 && s[last] == '*' )
                            last--;
                        swap(s[i],s[last]);
                        ans++;
                        val++;
                    }
                    else val--;
                }
                else
                {
                    val++;
                }
            }
            printf("%d\n",ans);
        }
    }
    return 0;
}

/*
//freopen("E:\\problem list\\codeblocks\\A\\input.txt","r",stdin);
//freopen("E:\\problem list\\codeblocks\\A\\standardoutput.txt","w",stdout);

1**3
12*34*56****
12*34*56***
12*34*56**
12*3*4
*11
1*1


11*11
*/

Do you know reverse Polish notation (RPN)? It is a known notation in the area of mathematics and computer science. It is also known as postfix notation since every operator in an expression follows all of its operands. Bob is a student in Marjar University. He is learning RPN recent days.

To clarify the syntax of RPN for those who haven't learnt it before, we will offer some examples here. For instance, to add 3 and 4, one would write "3 4 +" rather than "3 + 4". If there are multiple operations, the operator is given immediately after its second operand. The arithmetic expression written "3 - 4 + 5" in conventional notation would be written "3 4 - 5 +" in RPN: 4 is first subtracted from 3, and then 5 added to it. Another infix expression "5 + ((1 + 2) × 4) - 3" can be written down like this in RPN: "5 1 2 + 4 × + 3 -". An advantage of RPN is that it obviates the need for parentheses that are required by infix.

In this problem, we will use the asterisk "*" as the only operator and digits from "1" to "9" (without "0") as components of operands.

You are given an expression in reverse Polish notation. Unfortunately, all space characters are missing. That means the expression are concatenated into several long numeric sequence which are separated by asterisks. So you cannot distinguish the numbers from the given string.

You task is to check whether the given string can represent a valid RPN expression. If the given string cannot represent any valid RPN, please find out the minimal number of operations to make it valid. There are two types of operation to adjust the given string:

 

  1. Insert. You can insert a non-zero digit or an asterisk anywhere. For example, if you insert a "1" at the beginning of "2*3*4", the string becomes "12*3*4".
  2. Swap. You can swap any two characters in the string. For example, if you swap the last two characters of "12*3*4", the string becomes "12*34*".

 

The strings "2*3*4" and "12*3*4" cannot represent any valid RPN, but the string "12*34*" can represent a valid RPN which is "1 2 * 34 *".

Input

There are multiple test cases. The first line of input contains an integer T indicating the number of test cases. For each test case:

There is a non-empty string consists of asterisks and non-zero digits. The length of the string will not exceed 1000.

Output

For each test case, output the minimal number of operations to make the given string able to represent a valid RPN.

Sample Input

3
1*1
11*234**
*

Sample Output

1
0
2
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值