POJ3295Tautology(构造法)

Tautology
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 12088 Accepted: 4608

Description

WFF 'N PROOF is a logic game played with dice. Each die has six faces representing some subset of the possible symbols K, A, N, C, E, p, q, r, s, t. A Well-formed formula (WFF) is any string of these symbols obeying the following rules:

  • p, q, r, s, and t are WFFs
  • if w is a WFF, Nw is a WFF
  • if w and x are WFFs, Kwx, Awx, Cwx, and Ewx are WFFs.
The meaning of a WFF is defined as follows:
  • p, q, r, s, and t are logical variables that may take on the value 0 (false) or 1 (true).
  • K, A, N, C, E mean and, or, not, implies, and equals as defined in the truth table below.
Definitions of K, A, N, C, and E
     w  x  Kwx  Awx   Nw  Cwx  Ewx
  1  1  1  1   0  1  1
  1  0  0  1   0  0  0
  0  1  0  1   1  1  0
  0  0  0  0   1  1  1

tautology is a WFF that has value 1 (true) regardless of the values of its variables. For example, ApNp is a tautology because it is true regardless of the value of p. On the other hand, ApNq is not, because it has the value 0 for p=0, q=1.

You must determine whether or not a WFF is a tautology.

Input

Input consists of several test cases. Each test case is a single line containing a WFF with no more than 100 symbols. A line containing 0 follows the last case.

Output

For each test case, output a line containing tautology or not as appropriate.

Sample Input

ApNp
ApNq
0

Sample Output

tautology
not

这是一道构造法的题目,说白了就是自己构造了一些判断符号,比如K其实就是 && ,A就是 || ,N就是 !, C和E的话没有现成的,要自己去判断。

这道题目就是说给定了一个字符串,然后让你去判断,当中的变量只能是0或者1,如果有一种情况导致这个语句输出为0,那么就输出not,如果任何情况都不会为0,那就输出tautology。

本来我一直怀疑,这字符串最多可以长到100,如果是一堆的N之类的,变量如果有很多,30多个,都是不一样的,那么就有2的30次方种情况,肯定会T。我就一直想到底怎么写好,后来看了看题目,发现只有五个变量p,q,r,s,t。这最多也就2的五次方也就是32种情况,瞎暴力一通都能过的。

然后就是想法问题了,一开始我用栈stack直接遍历一遍把操作符和变量分别装到两个栈中,但是有一个很棘手的问题,那就是,你每次都要把这个语句给复制一遍啊,栈并不好复制出去,因为都是要一个一个出去的,要复制最后还是要归根到数组,所以想到了直接每次用数组来读。

不需要操作符栈,只需要数字栈,我直接从数组最后面开始读,读到KACE,就直接在数字栈中取出两个数字,判断,再放进数字栈中一个数字。如果是读到N,那么就在数字栈中取出一个数字,然后判断后放回数字栈中。如果读到变量名字,那就直接在map中读出这个字符对应的数字,放进数字栈中。

代码如下:

#include<cstdio>
#include<stack>
#include<set>
#include<map>
#include<iostream>
#include<cstring> 
using namespace std;
map<char, int>Map;
int k1, k2, len;
char str[105];

int func()
{
	stack<int> t_num;
	char ch;
	int tmp1, tmp2;
	for(int i = len - 1; i >= 0; i--)
		if(str[i] == 'K' || str[i] == 'A' || str[i] == 'C' || str[i] == 'E')
		{
			tmp1 = t_num.top();
			t_num.pop();
			tmp2 = t_num.top();
			t_num.pop();
			if(str[i] == 'K')
				t_num.push(tmp1 && tmp2);
			else if(str[i] == 'A')
				t_num.push(tmp1 || tmp2);
			else if(str[i] == 'C')
			{
				if(tmp1 == 0 && tmp2 == 1)
					t_num.push(0);
				else
					t_num.push(1);
			}
			else if(str[i] == 'E')
			{
				if(tmp1 == tmp2)
					t_num.push(1);
				else
					t_num.push(0);
			}
		}
		else if(str[i] == 'N')
		{
			tmp1 = t_num.top();
			t_num.pop();
			t_num.push(!tmp1);
		}
		else
			t_num.push(Map[str[i]]);

	tmp1 = t_num.top();
	while(!t_num.empty())
		t_num.pop();
	return tmp1;
}

int main()
{
	int flag;
	while(scanf("%s",str), str[0] != '0')
	{
		len = strlen(str);
		k1 = k2 = 0;
		flag = 1;
		for(int p = 0; p < 2 && flag; p++)
		{
			Map['p'] = p;
			for(int q = 0; q < 2 && flag; q++)
			{
				Map['q'] = q;
				for(int r = 0; r < 2 && flag; r++)
				{
					Map['r'] = r;
					for(int s = 0; s < 2 && flag; s++)
					{
						Map['s'] = s;
						for(int t = 0; t < 2 && flag; t++)
						{
							Map['t'] = t;
							if(func() == 0)
								flag = 0;
						}
					}		
				}		
			}		
		}
		if(flag)
			printf("tautology\n");
		else
			printf("not\n");
	}
	return 0;
} 

经过了这一道题目,我确实加深了C语言对运算符操作的方法,原来是这么的奇妙,一开始我真的写不出来的,因为我都是想从前往后遍历输入语句。

但是我觉得其实从前往后遍历也是可以的,但是想了想我觉得挺复杂的,比如CCCC100这种,我就需要一个运算栈来存放C,一直放,放到他读到数字为止,如果有N,比如CCCN100,那么读到N后自动读入后面一个数字判断然后放进去数字栈,写起来感觉还是很麻烦,还是从后往前遍历好了,就这么定了23333。


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值