POJ3295 Tautology(模拟栈)

传送门: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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值