1. 程式人生 > >ZOJ3829 (字尾表示式)詳解,適合新手

ZOJ3829 (字尾表示式)詳解,適合新手

題目放在最後面:

我想說,這個題對於不知道字尾表示式的人真的坑,看了半天題目結果還迷迷糊糊,但是這個卻是銅牌的題目,哎。

非常建議看一看相關部落格,關於他們的定義,推薦一篇寫的很好的部落格:

看完之後,解這個題就是分分鐘的事了,對於一個字尾表示式,我們的求法是:

從左至右掃描表示式,遇到數字時,將數字壓入堆疊,遇到運算子時,彈出棧頂的兩個數,用運算子對它們做相應的計算(次頂元素 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