1. 程式人生 > >2013NOIP普級組第二題--表示式的值(參考洛谷題解)

2013NOIP普級組第二題--表示式的值(參考洛谷題解)

一、題目描述

給定一個只包含加法和乘法的算術表示式,請你程式設計計算表示式的值。

輸入輸出格式

輸入格式:

輸入檔案為 expr.in。

輸入僅有一行,為需要你計算的表示式,表示式中只包含數字、加法運算子“+”和乘法運算子“*”,且沒有括號,所有參與運算的數字均為 0 到 2^31-1 之間的整數。輸入資料保證這一行只有 0~ 9、+、*這 12 種字元。

輸出格式:輸出檔名為 expr.out。

輸出只有一行,包含一個整數,表示這個表示式的值。注意:當答案長度多於 4 位時,

請只輸出最後 4 位,前導 0 不輸出。

輸入輸出樣例

輸入樣例#1: 複製
1+1*3+4
輸出樣例#1:
 複製
8
輸入樣例#2: 複製
1+1234567890*1
輸出樣例#2: 複製
7891
輸入樣例#3: 複製
1+1000000003*1
輸出樣例#3: 複製
4

說明

對於 30%的資料,0≤表示式中加法運算子和乘法運算子的總數≤100;

對於 80%的資料,0≤表示式中加法運算子和乘法運算子的總數≤1000;

對於 100%的資料,0≤表示式中加法運算子和乘法運算子的總數≤100000。

二、解題思路

思路一

到題目,首先分析:

1、乘法一定先做

2、而所有的連乘都是從左往右算

3、更重要的是,如果遇到加號,說明連乘必定完結,這時候再累加即可

定義——塊:一段連乘

首先,題目中必有x個加號,將式子分為x+1個塊,而這些塊最終要做的是相加,所以從左往右算

用ans表示當前累加和,t1表示累乘結果,t2表示當前這個數(當前要乘的數),t2的讀入方式類似C++的讀入優化,按位讀入然後乘以10加當前位

框架

do ch=getchar()  

switch(ch)  

case'+':ans累加  

case'*':t1累乘

思路二

輸入可以直接scanf(“%d”),然後scanf(“%c”)就行了,不會出錯。每一次判斷其上一個運算子,進行相應的處理,然後新增到sum中。這裡注意一下,如果開int,有可能兩個2^31-1相乘,這樣可能(我也沒試過)會爆。所以都用long long存,保證能AC。最後如果scanf(“%c”)==EOF,則進行最後的處理,然後break即可。

只輸出後四位,則每一步操作都mod10000即可。

思路三

棧(stack)

(1)讀入字元,當其為”+“時,我們先不管;當其為數時則入棧;當其為“*”時我們繼續往後讀一個數,再從棧中取出一個數與其相乘,將其乘積入棧;

(2)第一項執行完畢後,我們將棧中的元素累加,再輸出和。顯然,這就是我們想要的答案。

三、參考程式碼

(1)非棧的思想實現

#include<cstdio>

#include<iostream>

#include<algorithm>

#include<cmath>

#include<cstring>

#include<string>

using namespace std;

int main()

{

    long long shu,sum=0,cj,sg;//記得sum初始值賦為0;cj為其中一段運算(即一段連續的乘積)的值

    char ch=0,xg;//ch儲存上一個運算子,xg為新讀入的運算子

    bool tf=true;

    while(tf)

    {

        scanf("%lld",&shu);

        tf=scanf("%c",&xg)==1?true:false;//如果下一個沒有運算子了,則tf=false,既保證了此次迴圈的正常執行,又能在下一遍迴圈跳出

        if(ch==0)cj=shu;//如果是剛開始讀入,則直接賦值

        if(ch=='+')sum=(sum+cj)%10000,cj=shu;//如果上一個操作是加法,則將前一段的值加入到sum中,然後再更新此新段的值

        if(ch=='*')cj=(cj*shu)%10000;//如果上一個運算仍是乘法,則將此數乘入本段的值中

        if(!tf)sum=(sum+cj)%10000;//如果是最後一個元素,則進行最後的更新

        ch=xg;//將下一個讀入的運算子作為新的一個迴圈的上一個運算子,並繼續迴圈

    }

    printf("%lld",sum);//輸出

    return 0;

}

(2)棧的思想實踐

#include<cstdio>

#include<iostream>

#include<cstring>

#include<stack>                                         //c++自帶棧在STL模板庫裡呼叫

using namespace std;

string x;

stack <char> s;                                                               //算符棧

stack <long long> n;                                                      //數字棧

long long ans;

int len;

int main()

{

    int i=0;

    getline(cin,x);

    len=x.length();

    while (i<=len-1)

    {

        int t=0;

        bool f=false;

        while (x[i]>='0'&&x[i]<='9')                                          //進數字的操作

        {

            t=t*10+(x[i]-48);

            f=true;

            i++;

        }

        if (f)

        {

            n.push(t%10000);

            if (s.size()>=1&&s.top()=='*')                                               //處理乘號

            {

                int k=n.top();                                                              

                s.pop();

                n.pop();                                                  //先把top的數出棧,再讓top-1的數成為top,讓他們相乘,再讓top出棧,讓乘積進棧

                k*=n.top();                                                     //這幾行碼核心內容就是n[--top]=n[top]*n[top+1];

                n.pop();

                n.push(k%10000);

            }

        }

        if (x[i]=='+'||x[i]=='*')

        {

            s.push(x[i]);

            i++;

        }

    }

    int size=n.size();

    for (i=1;i<=size;i++)                                                                      //計算和

    {

        ans+=n.top();

        n.pop();

        ans%=10000;

    }

    printf("%lld",ans%10000);

    return 0;

}