b504 等價表示式 NOIP2005第4題

2021-09-28 10:07:29 字數 3730 閱讀 6062

time limit: 1 second

memory limit: 50 mb

明明進了中學之後,學到了代數表示式。有一天,他碰到乙個很麻煩的選擇題。這個題目的題幹中首先給出了乙個代數表示式,然後列出了若干選項,每個選項也是乙個代數表示式,題目的要求是判斷選項中哪些代數表示式是和題幹中的表示式等價的。這個題目手算很麻煩,因為明明對計算機程式設計很感興趣,所以他想是不是可以用計算機來解決這個問題。假設你是明明,能完成這個任務嗎?這個選擇題中的每個表示式都滿足下面的性質:

1. 表示式只可能包含乙個變數『a』。

2. 表示式**現的數都是正整數,而且都小於10000。

3. 表示式中可以包括四種運算『+』(加),『-』(減),『*』(乘),『^』(乘冪),以及小括號『(』,『)』。小括號的優先順序最高,其次是『^』,然後是『*』,最後是『+』和『-』。『+』和『-』的優先順序是相同的。相同優先順序的運算從左到右進行。(注意:運算子『+』,『-』,『*』,『^』以及小括號『(』,『)』都是英文本元)

4. 冪指數只可能是1到10之間的正整數(包括1和10)。

5. 表示式內部,頭部或者尾部都可能有一些多餘的空格。

下面是一些合理的表示式的例子:

((a^1) ^ 2)^3,a*a+a-a,((a+a)),9999+(a-a)*a,1 + (a -1)^3,1^10^9……

共n+2行;

第一行是題幹中的表示式。

第二行是乙個整數n(2 <= n <= 26),表示選項的個數。

接下來的n行,每行包括乙個選項中的表示式。這n個選項的標號分別是a,b,c,d…… 輸入中的表示式的長度都不超過50個字元,而且保證選項中總有表示式和題幹中的表示式是等價的。

包含1行,這一行包括一系列選項的標號,表示哪些選項是和題幹中的表示式等價的。選項的標號按照字母順序排列,而且之間沒有空格。

( a + 1) ^2

3(a-1)^2+4*a

a + 1+ a

a^2 + 2 * a * 1 + 1^2 + 10 -10 +a -a

ac
30%的資料滿足:表示式中只可能出現兩種運算子『+』和『-』

對於其他的資料滿足:對於其它的資料,四種運算子『+』,『-』,『*』,『^』在表示式中都可能出現

100%的資料滿足:表示式中都可能出現小括號『(』和『)』

【題解】

這是一道表示式求值的問題。

判斷是否等價。需要用一系列的數字來判斷。即把a代成相同的數字然後求兩個表示式的值,如果相同則判斷為相同。為了防止偶然性誤差。得多弄幾個a值。要在代所有的數字答案都相同。才能判斷這個表示式和目標表示式是等價的。

用二分的方法求表示式的值。

具體的。先找到表示式中。計算優先級別最小的操作符。然後以這個操作符為劃分依據,分為左半邊和右半邊。進行遞迴的過程。如果當前處理的字元只有數字。則直接返回這個數字。如果只有a則返回我們當前給a定義的值(程式中有進行3次驗算);

然後不能直接把答案計算出來。因為可能會溢位。所以要取模。這個用來取模的數字,不能隨便取。不然會錯解。

然後是一開始輸入的表示式。

它可能會出現右括號多餘的情況。需要去除。

同時也可能出現左括號多餘的情況。同樣要去除。

去除的方法要看我的程式裡的操作。不能簡單的看到乙個右括號就去掉。

//還有多餘空格也要去掉。

【**】

#include #include #include #include using namespace std; 

const int xx[4] = ;

const int mo = 2551;

string s;

int daiti,ans[4],n;

void check(string & s) //因為是要直接對s處理,所以要加個&表示對s操作。不加的話沒有效果。

if ( b > 0) //如果左括號多了

for (int i = 1;i <= l;i++)

if (b >0 && s[i] == '(') //遇到乙個左括號就直接置為標記符

s[i] = '$',b--;

else

if (b == 0)

break;

l = s.size()-1;

string ss = " ";

for (int i = 1;i <= l;i++) //把不是標記符的記錄下來,也即去除多餘括號的過程

if (s[i] != '$')

ss += s[i];

s = ss;

}bool reducebracket(string & s)

s = s.erase(l,1);

s = s.erase(1,1); //否則去除括號並返回true表示要繼續嘗試去除括號

return true;

}char cmp(char x,char y) //判斷x操作符和y操作符哪乙個的計算優先級別更低

int find(string s)

while (b != 0);

}else //如果是操作符,就判斷一下是否比當前找到的操作符級別更低,如果是就更新

if (

(s[i] == '*' || s[i] == '+' || s[i] == '^') ||

(s[i] == '-' && i > 1 && (s[i-1] == ')' || (s[i-1] >='0' && s[i-1] <= '9')

|| (s[i-1] == 'a') ))

)i++; //不管這個字元是什麼都要遞增迴圈變數

}else

i++;

} return k;

}int x_y(int x, int y) //獲取x^y mod mo 的值

int reduce(string s)

else //減號的話要判斷是不是因為這個數字是負數。

if (s[i] == '-' && i > 1 && (s[i-1] == ')' || (s[i-1] >='0' && s[i-1] <= '9')

|| (s[i-1] == 'a') )) //如果這個負號前面有右括號,或者a或者數字。則一定是運算子

if (not judge) //如果沒有運算子則就是乙個數字 直接轉換成數字然後返回就可以了

bool flag = reducebracket(s); //這是去除兩邊的括號 如 (1+3)則這步會去除兩邊括號變成1+3

while (flag) //可能有多層括號所以要多次去除

int k = find(s); //k表示s這個字串裡面運算優先級別最小的操作符所在的位置

char key = s[k]; //獲取這個操作符是什麼

string s1 = s.substr(0,k); //然後把操作符的左邊和右邊擷取出來

s = s.erase(0,k+1);

s = " " + s; //要在右邊前面加上空格。便於操作

string s2 = s;

int x = reduce(s1),y = reduce(s2);//遞迴獲取左邊和右邊的值

switch (key) //判斷這個操作符是什麼,然後做相應的運算。 }

void input_data()

scanf("%d",&n);

getchar();//在用getline之前一定要加一句getchar

for (int i = 1;i <= n;i++) //讀入n個表示式

}}int main()

NOIP2005 等價表示式

等價表示式 equal.pas c cpp 問題描述 明明進了中學之後,學到了代數表示式。有一天,他碰到乙個很麻煩的選擇題。這個題目的題幹中首先給出了乙個代數表示式,然後列出了若干選項,每個選項也是乙個代數表示式,題目的要求是判斷選項中哪些代數表示式是和題幹中的表示式等價的。這個題目手算很麻煩,因為...

NOIP 2005 等價表示式

題目描述 明明進了中學之後,學到了代數表示式。有一天,他碰到乙個很麻煩的選擇題。這個題目的題幹中首先給出了乙個代數表示式,然後列出了若干選項,每個選項也是乙個代數表示式,題目的要求是判斷選項中哪些代數表示式是和題幹中的表示式等價的。這個題目手算很麻煩,因為明明對計算機程式設計很感興趣,所以他想是不是...

NOIP2005 等價表示式

明明進了中學之後,學到了代數表示式。有一天,他碰到乙個很麻煩的選擇題。這個題目的題幹中首先給出了乙個代數表示式,然後列出了若干選項,每個選項也是乙個代數表示式,題目的要求是判斷選項中哪些代數表示式是和題幹中的表示式等價的。這個題目手算很麻煩,因為明明對計算機程式設計很感興趣,所以他想是不是可以用計算...