- 題目鏈接:http://noi.openjudge.cn/ch0303/6263/
- 總時間限制: 1000ms 內存限制: 65536kB
- 描述
-
輸入一個布爾表達式,請你輸出它的真假值。 比如:( V | V ) & F & ( F | V )
V表示true,F表示false,&表示與,|表示或,!表示非。
上式的結果是F - 輸入
- 輸入包含多行,每行一個布爾表達式,表達式中可以有空格,總長度不超過1000
- 輸出
- 對每行輸入,如果表達式為真,輸出"V",否則出來"F"
- 樣例輸入
-
( V | V ) & F & ( F| V) !V | V & V & !F & (F | V ) & (!F | F | !V & V) (F&F|V|!V&!F&!(F|F&V))
- 樣例輸出
-
F V V
分析:(來源:http://blog.csdn.net/INCINCIBLE/article/details/51151222?locationNum=5&fps=1)
原理很簡單,將中綴表達式轉化為前綴表達式在計算,只是代碼實現比較麻煩。
中綴轉前綴的步驟如下:
(1) 首先構造一個運算符棧(也可放置括號),運算符(以括號分界點)在棧內遵循越往棧頂優先級不降低的原則進行排列。
(2)從右至左掃描中綴表達式,從右邊第一個字符開始判斷:
如果當前字符是數字,則分析到數字串的結尾並將數字串直接輸出。
如果是運算符,則比較優先級。如果當前運算符的優先級大於等於棧頂運算符的優先級(當棧頂是括號時,直接入棧),則將運算符直接入棧;否則將棧頂運算符出棧並輸出,直到當前運算符的優先級大於等於棧頂運算符的優先級(當棧頂是括號時,直接入棧),再將當前運算符入棧。
如果是括號,則根據括號的方向進行處理。如果是右括號,則直接入棧;否則,遇左括號前將所有的運算符全部出棧並輸出,遇右括號后將左右的兩括號一起刪除。
(3) 重復上述操作(2)直至掃描結束,將棧內剩余運算符全部出棧並輸出,再逆綴輸出字符串。中綴表達式也就轉換為前綴表達式了。
右括號有最高的優先級,左括號優先級最低。
代碼:
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<queue> 5 #include<stack> 6 #include<cstring> 7 using namespace std; 8 char calculate(char x, char y,char oper )// 計算 x oper y 9 { 10 bool a=(x=='V'),b=(y=='V'),ans; 11 if(oper=='|') ans=(a||b); 12 else if(oper=='&') ans=(a&&b); 13 return ans?'V':'F'; 14 } 15 char reverse(char x) //將邏輯值取反。其實就是‘!’運算符 16 { 17 if(x=='V')return 'F'; 18 return 'V'; 19 } 20 int main() 21 { 22 string in; 23 int i,j,len; 24 25 while(getline(cin,in)) 26 { 27 stack<char> Oper,num; //oper保存運算符,num保存運算結果 28 queue<char> s; //s就是前綴表達式 29 len=in.length(); 30 i=len; 31 in=" "+in; 32 while(i>0)// 從右往左,中綴表達式轉前綴表達式 33 { 34 if(in[i]==' ') 35 { 36 i--;continue; 37 } 38 else if(isalpha(in[i])) s.push(in[i--]);//isalpha()函數:如果參數是字母字符,函數返回非零值,否則返回零值 39 else if(in[i]=='!') s.push(in[i--]); //最高級的運算,直接進入表達式(這里主要是因為!運算符是單目運算符) 40 else 41 { 42 if(in[i]=='&'||in[i]=='|'||in[i]==')') //低級運算,進棧 43 Oper.push(in[i--]); 44 else if(in[i]=='(') //一個括號結束,彈出中間的所有運算符 45 { 46 while(Oper.top()!=')') 47 { 48 s.push(Oper.top()); 49 Oper.pop(); 50 } 51 Oper.pop(); 52 i--; 53 } 54 } 55 } 56 while(!Oper.empty()) //棧中剩下的運算符 57 s.push(Oper.top()),Oper.pop(); 58 59 while(!s.empty()) //計算前綴表達式 60 { 61 char ch=s.front(); s.pop(); 62 if(isalpha(ch)) num.push(ch); 63 else Oper.push(ch); 64 if(!num.empty()&&!Oper.empty()&&Oper.top()=='!') //單目運算符‘!’; 65 { 66 char x=num.top(); 67 num.pop();Oper.pop(); 68 num.push(reverse(x)); 69 } 70 else if(num.size()>=2&&!Oper.empty()) //雙目運算符 71 { 72 char oper=Oper.top(),x,y; 73 Oper.pop(); 74 x=num.top();num.pop(); 75 y=num.top();num.pop(); 76 num.push(calculate(x,y,oper)); 77 } 78 } 79 cout<<num.top()<<endl; 80 } 81 }
另外,可以參考http://www.ithao123.cn/content-10400535.html
第二種思路,遞歸求解。
代碼來源:北大郭煒老師MOOC課程的代碼。可以參考中綴表達式計算這篇文章的分析。
1 #include <iostream> 2 #include <cstdio> 3 using namespace std; 4 5 char wholeExp[1500];//表示整個表達式的字符串 6 int ptr = 0; 7 8 bool exp();//讀入一個表達式並返回其值 9 bool item();//讀入一個項並返回其值 10 bool factor();//讀入一個因子並返回其值 11 bool notExp();//將表達式取反的操作 12 /* 13 表達式:由單獨的"項"或者"項"與"|"運算符連接形成; 14 項:由單獨的"因子"或"因子"和&運算符連接而成; 15 因子:可以是單獨的V或F,也可以是用括號括起來的"表達式"。 16 */ 17 int main() 18 { 19 freopen("6263.in","r",stdin); 20 int t = 1;//表示第t個測試樣例 21 char c; 22 int i = 0; 23 int n = EOF + 1; 24 while(n != EOF) 25 { 26 n = scanf("%c",&c); 27 if( n == EOF || c == '\n') 28 { 29 wholeExp[i] = '\0'; 30 if( i > 0) 31 { 32 ptr = 0; 33 bool res = exp(); 34 if (res) { printf("Expression %d: V\n",t++); } 35 else printf("Expression %d: F\n",t++); 36 /*if (res) { printf("V\n",t++); } 37 else printf("F\n",t++);*/ 38 } 39 i = 0; 40 } 41 else if( c != ' ') wholeExp[i++] = c; 42 } 43 return 0; 44 } 45 46 bool exp() //讀入一個表達式並返回其值 47 { 48 bool result = item(); 49 while(wholeExp[ptr] == '|' ) 50 { 51 ++ptr; 52 result = result | item();//注意:這里的或運算不能用C語言邏輯或運算符,因為邏輯或運算符在編譯器處理完以后有短路特性,可能會忽略后面的輸入。比如(V|V)&F,若是用邏輯或,可能只掃描到第一個V就返回邏輯真,不再繼續往后掃描了。但是其實應該是邏輯假。 53 } 54 return result; 55 } 56 57 bool item() //讀入一個項並返回其值 58 { 59 bool result = factor(); 60 while(wholeExp[ptr] == '&') 61 { 62 ++ptr; 63 result = result & factor();//同樣地,這個地方不能用邏輯與運算符,否則會錯忽略后面應該掃描的東西從而返回錯誤的結果。比如(F&V)|V。 64 } 65 return result; 66 } 67 68 bool factor() //讀入一個因子並返回其值 69 { 70 bool result; 71 switch( wholeExp[ptr]) 72 { 73 case 'F': 74 ++ptr; 75 return false; 76 break; 77 case 'V': 78 ++ptr; 79 return true; 80 break; 81 case '(': 82 ++ptr; 83 result = exp(); 84 ++ptr; //skip ')' 85 return result; 86 break; 87 case '!': 88 result = notExp(); 89 return result; 90 break; 91 } 92 } 93 94 bool notExp() //將表達式取反的操作 95 { 96 //wholeExp[ptr] == '!' when called; 97 ptr++; 98 bool result; 99 switch(wholeExp[ptr]) 100 { 101 case 'F': 102 ++ptr; 103 return true; 104 break; 105 case 'V': 106 ++ptr; 107 return false; 108 break; 109 case '(': 110 ++ptr; 111 result = exp(); 112 ++ptr; //skip ')' 113 return !result; 114 break; 115 case '!': 116 result = notExp(); 117 return !result; 118 break; 119 } 120 }