传送门:http://poj.org/problem?id=3295
题意:用5种字母表示不同运算符,并可能会出现5个变量,如果计算结果永远为真,输出Tautology,否则输出not;
运算规则如下,
K a && b; //与
A a || b; //或
N !a; //取反
C (!a)||b;
E !(a^b); //同或
模拟栈来进行计算,并且用递归写计算过程,还是比较好的练手模拟题。
代码:
//Accepted 680K 0MS G++ 1752B
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<string>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<cctype>
#include<iostream>
#include<algorithm>
using namespace std;
#define ff(x) (x=='1')?'0':'1'
char input[110];
map<char, int> id;
int cnt;
char st[200];//用数组模拟栈而不用stl的原因是要操作栈顶之后的几个元素,封装了之后就不好操作了,还是自己模拟方便
int top;
inline int ID(char x)//标记变量
{
if (id.count(x)) return id[x];
return id[x] = cnt++;
}
inline bool val(int n,char x)
{
return n&(1 << ID(x));//计算当前变量的值
}
void cal()
{
if (!isdigit(st[top])) return;
if (top == 0) return;
if (st[top - 1] == 'N') {//N计算
st[top - 1] = ff(st[top]);//ff用define定义成取反了
top--;
}
else if (top >= 2 && isdigit(st[top - 1]) && isupper(st[top - 2])) {//其余计算
int v1 = st[top] - '0', v2 = st[top - 1] - '0';//记录下方两个变量的值
top -= 2;
switch (st[top])
{
case 'K':st[top] = (v1&&v2) + '0'; break;
case 'A':st[top] = (v1 || v2) + '0'; break;
case 'C':st[top] = ((!v2) || v1) + '0'; break;
case 'E':st[top] = !(v1^v2) + '0'; break;//同或,看成异或了wa了半天才发现
}
}
else return;
cal();//递归计算栈顶的值
}
int main()
{
// freopen("D://input.txt","r",stdin);
// freopen("D://output.txt","w",stdout);
while (scanf("%s", input) != EOF&&input[0] != '0')
{
id.clear();
cnt = 0;//变量个数
int i, j;
for (i = 0; input[i]; i++)
{
if (islower(input[i]))//给变量做标记
ID(input[i]);
}
bool ok = true;//记录是否一直是真
for (i = 0; ok&&i < (1 << cnt); i++)//枚举所有情况,因为变量最多5个,所以最多是1<<5=32种情况
{
memset(st, 0, sizeof(st));//清空栈
top = -1;//初始化头指针
for (j = 0; input[j]; j++)
{
if (islower(input[j]))
st[++top] = val(i, input[j]) + '0';
else st[++top] = input[j];
cal();
}
if (top != 0)
cal();
if (st[0] == '0')
ok = false;
}
if (!ok)
printf("not\n");
else printf("tautology\n");
}
// printf("%.6f\n", (double)clock() / CLOCKS_PER_SEC);
return 0;
}