题目大意
给定一个由10种字符(p,q,r,s,t,N,K,A,C,E)组成的逻辑表达式,其中pqrst为逻辑变量,NKACE为逻辑运算符,他们的含义分别是
- K==and:x && y
- N==not:!x
- A==or:x || y
- C==implies:(!x)||y
- E==equals:x==y
要求判断这个逻辑表达式是否为重言式,如果是就输出tautology,否则输出not
思路
根据题设,我们不难判断,单目运算符一定在整个字符串的后半部分,双目运算符一定在整个字符串的前半部分。例如ApNp,它应该被判为A(p,N(p)),所以上述结论的正确性是显然的。那么就可以像常规的表达式计算一样,从尾部压入栈,然后弹一个计算一个。
因为只有5个逻辑变量,所以最多只会有2^5=32种情况,依次枚举就好。
代码
我的写法
五重循环枚举每一位,最内层去枚举长度。
#include <stack>
#include <vector>
#include <cstdio>
#include <iostream>
using namespace std;
string str;
bool input(stack<int>& sta, char ss, int p, int q, int r, int s, int t) {
switch(ss) {
case 'p' : sta.push(p); return true;
case 'q' : sta.push(q); return true;
case 'r' : sta.push(r); return true;
case 's' : sta.push(s); return true;
case 't' : sta.push(t); return true;
}
return false;
}
void operated(stack<int>& sta, char ss) {
int a, b;
switch(ss) {
case 'K' : {
a = sta.top();sta.pop();
b = sta.top();sta.pop();
sta.push(a && b);
break;
}
case 'N' : {
a = sta.top();sta.pop();
sta.push(!a);
break;
}
case 'A' : {
a = sta.top();sta.pop();
b = sta.top();sta.pop();
sta.push(a || b);
break;
}
case 'E' : {
a = sta.top();sta.pop();
b = sta.top();sta.pop();
sta.push(a == b);
break;
}
case 'C' : {
a = sta.top();sta.pop();
b = sta.top();sta.pop();
sta.push(!a || b);
break;
}
}
}
int main() {
while(cin >> str) {
if(str[0] == '0') break;
int len = str.length();
stack<int> sta;
bool flag = 1;
for(int p = 0; p <= 1; p++) {
for(int q = 0; q <= 1; q++) {
for(int r = 0; r <= 1; r++) {
for(int s = 0; s <= 1; s++) {
for(int t = 0; t <= 1; t++) {
for(int l = len; l >= 0; l--) {//倒叙读入
if(!input(sta, str[l], p, q, r, s, t)) {
//如果当前字符不是变量,就根据运算符计算
operated(sta, str[l]);
}
}
//只要出现真值为0的项就可以退出了
if(!sta.top()) {flag = 0; break;}
}
if(!flag) break;
}
if(!flag) break;
}
if(!flag) break;
}
if(!flag) break;
}
flag ? cout << "tautology\n" : cout << "not\n";
}
return 0;
}
另外一种写法
在网上冲浪的时候看到了另一种用位运算来枚举的写法,属实高级且优雅,但碍于本人稀烂的位运算水平,只能在此贴出代码,日后水平渐长才能尝试读懂。
//来源:https://www.cnblogs.com/shenben/p/5646335.html
#include<iostream>
using namespace std;
int cnt;
char str[101];
bool step(char str[101],int tk){
cnt++;
switch(str[cnt]){
case 'p':return tk&1;
case 'q':return(tk>>1)&1;
case 'r':return(tk>>2)&1;
case 's':return(tk>>3)&1;
case 't':return(tk>>4)&1;
case 'N':return !step(str,tk);
case 'K':return step(str,tk)&step(str,tk);
case 'A':return step(str,tk)|step(str,tk);
case 'C':return !step(str,tk)|step(str,tk);
case 'E':return step(str,tk)==step(str,tk);
}
}
bool judge(char str[101]){
for(int i=0;i<32;i++){
cnt=-1;
if(!step(str,i)) return 0;
}
return 1;
}
int main(){
while(cin>>str){
if(str[0]=='0') break;
if(judge(str))
cout<<"tautology"<<endl;
else
cout<<"not"<<endl;
}
return 0;
}