构造法 | 栈 | POJ3295.Tautology
Link:Tautology
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.
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
A 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
Source
Waterloo Local Contest, 2006.9.30
题意
p q r s t 为5个逻辑变量,取值可取为0, 1
K A N C E为5种逻辑运算,分别为 与,或, 非, 蕴含,相等;
即 Kwx = w && x; Awx = w || x; Nw = !w; Cwx = (!w) || x; Ewx = (w == x);
先给出一个合法的合式公式,判断其是否为永真式。
思路
首先分析 ApNp的运算法则:ApNp = A( p, N(p) ); 它是一种层层嵌套的运算方法,让我想起了后缀表达式的计算,例如abc+*,采用栈的方式,从左到右进行压栈。此题的运算方式类似于后缀表达式,但由于运算符在前,变量在后,所以仿照后缀表达式求值的方法,应该从尾部向前迭代。迭代方式为:
1.如果当前字符为变量,则将其压入变量栈
2.如果当前字符为运算符,首先看运算符类型
a.若当前是一目运算符(N),则出栈一个元素,运算后将结果压入变量栈
b.若当前是二目运算符,将出栈两个元素运算后将其压入变量栈
将此次迭代完成时,变量栈只有一个元素,他就是此合式计算的结果。
题目要求判断为永真式,共给出5个变量,所以让每个变量分别取0,1,共32种取值方式,若所有情况下该式结果均为1,则此式为永真式,否则不是。
小技巧:5个变量分别取0,1一般而言采取5个循环,这里采用了一个char变量的后五位对应5个变量的取值。
做法是设置一个编码code从0x00自增到0x1F; 要取每一位的值时,设置这一位的掩码,编码与掩码相与后向右移位即可得到这一位的值。
例如: char code = 0x05, 即0B00000101,要取第3位r的值,则设置r的掩码MASK=0x04, 相与后得到0x04,向右移两位即得到当前值。即(code&R_MASK)>>2
这道题A了好久,说一下我踩过的坑
1. 这里设置了一个全局的栈, 所以在计算每一个code相应的合式的值时应该将栈初始化。就因为我这个没有注意debug了好久
2.遍历所有取值的条件应该为 code <= ENUM_CODE 而不是<
代码
#include <iostream>
#include <cstring>
#include <stack>
#define N(w) (!(w))
#define K(w,x) (w&&x)
#define A(w,x) (w||x)
#define C(w,x) ((!w)||x)
#define E(w,x) (w==x)
using namespace std;
const char P_MASK = 0x01;
const char Q_MASK = 0x02;
const char R_MASK = 0X04;
const char S_MASK = 0X08;
const char T_MASK = 0X10;
const int MAX_LEN = 101;
const char ENUM_CODE = 0x1F;
char code = 0x00;
bool flag;
char WFF[MAX_LEN];
stack<char> var;
char toValue( char c )
{
char val = 2;
switch( c )
{
//注意: 运算符优先级 == 高于 &
case 'p': val = ((code&P_MASK)==0?0:1); break;
case 'q': val = (((code&Q_MASK)>>1)==0?0:1); break;
case 'r': val = (((code&R_MASK)>>2)==0?0:1); break;
case 's': val = (((code&S_MASK)>>3)==0?0:1); break;
case 't': val = (((code&T_MASK)>>4)==0?0:1); break;
default : val = 2;
}
//cout << "val: " << val << endl;
return val;
}
bool isTautology()
{
int len = strlen(WFF);
char c, value;
char w, x;
int i;
for( i = len-1; i >= 0; i-- )
{
c = WFF[i];
value = toValue(c);
if( value < 2 )
var.push( value );
else if( c == 'N' )
{
w = var.top();
var.pop();
var.push( N(w) );
}
else
{
w = var.top();
var.pop();
x = var.top();
var.pop();
if( c == 'K' ) var.push( K(w,x) );
else if( c == 'A' ) var.push( A(w,x) );
else if( c == 'C' ) var.push( C(w,x) );
else var.push( E(w,x) );
}
}
c = var.top();
if( c == 1 )
return true;
else
return false;
}
int main()
{
while( cin >> WFF && WFF[0] != '0' )
{
flag = true;
for( code = 0; code <= ENUM_CODE; code++)
{
while( !var.empty() )
var.pop();
flag = isTautology();
if( !flag )
{
cout << "not" << endl;
break;
}
}
if( flag )
cout << "tautology" << endl;
}
}
本文介绍了一种算法,用于判断一个合式公式是否为永真式。通过使用栈来迭代计算合式公式的值,并遍历所有变量取值情况,最终确定公式是否在所有情况下都为真。

1042

被折叠的 条评论
为什么被折叠?



