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個塊,而這些塊最終要做的是相加,所以從左往右算
框架
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即可。
思路三
棧(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;
}