#include <stdio.h>
#include <malloc.h>
#include <string.h>
struct operatorParam{
char operand;
char operandRes;
struct operatorParam * left; //For p q r s t and N, only one param.
struct operatorParam * right;
};
typedef struct operatorParam operandParam;
void traverseOperandTree(operandParam * operandTreeHead) {
if (operandTreeHead == NULL) {
return;
}
printf("%c ( ", operandTreeHead->operand);
traverseOperandTree(operandTreeHead->left);
printf(" )( ");
traverseOperandTree(operandTreeHead->right);
printf(" ) ");
}
char * buildOperandNode(char * WFF, operandParam ** parentNodeLink) {
if (WFF == NULL) {
return NULL;
}
if (*WFF == '\0') {
return NULL;
}
(*parentNodeLink) = (operandParam *)malloc(sizeof(operandParam));
(*parentNodeLink)->operand = WFF[0];
if (WFF[0] == 'p' ||
WFF[0] == 'q' ||
WFF[0] == 'r' ||
WFF[0] == 's' ||
WFF[0] == 't') {
(*parentNodeLink)->left = NULL;
(*parentNodeLink)->right = NULL;
return WFF + 1;
} else if (WFF[0] == 'N') {
(*parentNodeLink)->right = NULL;
return buildOperandNode(WFF+1, &((*parentNodeLink)->left));
} else if (WFF[0] != 0){
char * nextOperandPos = buildOperandNode(WFF+1, &((*parentNodeLink)->left));
return buildOperandNode(nextOperandPos, &((*parentNodeLink)->right));
} else {
return NULL;
}
}
void buildOperandTree(char * WFF, operandParam ** operandTreeHead) {
buildOperandNode(WFF, operandTreeHead);
}
bool KOP(bool x, bool y) {
return x&y;
}
bool AOP(bool x, bool y) {
return x|y;
}
bool NOP(bool x) {
return !x;
}
bool COP(bool x, bool y) {
if (x == 1 && y == 0) {
return 0;
}
return 1;
}
bool EOP(bool x, bool y) {
return !(x^y);
}
bool getTreeRes(operandParam * operandTreeHead, bool p, bool q, bool r, bool s, bool t) {
switch(operandTreeHead->operand) {
case 'p':
return p;
case 'q':
return q;
case 'r':
return r;
case 's':
return s;
case 't':
return t;
case 'N':
return NOP(getTreeRes(operandTreeHead->left, p, q, r, s, t));
case 'A':
return AOP(getTreeRes(operandTreeHead->left, p, q, r, s, t),
getTreeRes(operandTreeHead->right, p, q, r, s, t));
case 'K':
return KOP(getTreeRes(operandTreeHead->left, p, q, r, s, t),
getTreeRes(operandTreeHead->right, p, q, r, s, t));
case 'C':
return COP(getTreeRes(operandTreeHead->left, p, q, r, s, t),
getTreeRes(operandTreeHead->right, p, q, r, s, t));
case 'E':
return EOP(getTreeRes(operandTreeHead->left, p, q, r, s, t),
getTreeRes(operandTreeHead->right, p, q, r, s, t));
default:
return false;
}
}
bool checkAllOperandTreeCombination(operandParam * operandTreeHead) {
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++) {
if (!getTreeRes(operandTreeHead, p, q, r, s, t)) {
return false;
}
}
}
}
}
}
return true;
}
bool checkTautology(char * WFF) {
if (strlen(WFF) == 0) {
return false;
}
if (WFF[0] == 'p' ||
WFF[0] == 'q' ||
WFF[0] == 'r' ||
WFF[0] == 's' ||
WFF[0] == 't') {
return false;
}
operandParam * operandTreeHead;
buildOperandTree(WFF, &operandTreeHead);
// traverseOperandTree(operandTreeHead);
return checkAllOperandTreeCombination(operandTreeHead);
}
int main() {
char WFF[101];
while(1) {
scanf("%s", WFF);
if (!strcmp(WFF, "0")) {
return 0;
} else {
if (checkTautology(WFF)) {
printf("tautology\n");
} else {
printf("not\n");
}
}
}
#include <malloc.h>
#include <string.h>
struct operatorParam{
char operand;
char operandRes;
struct operatorParam * left; //For p q r s t and N, only one param.
struct operatorParam * right;
};
typedef struct operatorParam operandParam;
void traverseOperandTree(operandParam * operandTreeHead) {
if (operandTreeHead == NULL) {
return;
}
printf("%c ( ", operandTreeHead->operand);
traverseOperandTree(operandTreeHead->left);
printf(" )( ");
traverseOperandTree(operandTreeHead->right);
printf(" ) ");
}
char * buildOperandNode(char * WFF, operandParam ** parentNodeLink) {
if (WFF == NULL) {
return NULL;
}
if (*WFF == '\0') {
return NULL;
}
(*parentNodeLink) = (operandParam *)malloc(sizeof(operandParam));
(*parentNodeLink)->operand = WFF[0];
if (WFF[0] == 'p' ||
WFF[0] == 'q' ||
WFF[0] == 'r' ||
WFF[0] == 's' ||
WFF[0] == 't') {
(*parentNodeLink)->left = NULL;
(*parentNodeLink)->right = NULL;
return WFF + 1;
} else if (WFF[0] == 'N') {
(*parentNodeLink)->right = NULL;
return buildOperandNode(WFF+1, &((*parentNodeLink)->left));
} else if (WFF[0] != 0){
char * nextOperandPos = buildOperandNode(WFF+1, &((*parentNodeLink)->left));
return buildOperandNode(nextOperandPos, &((*parentNodeLink)->right));
} else {
return NULL;
}
}
void buildOperandTree(char * WFF, operandParam ** operandTreeHead) {
buildOperandNode(WFF, operandTreeHead);
}
bool KOP(bool x, bool y) {
return x&y;
}
bool AOP(bool x, bool y) {
return x|y;
}
bool NOP(bool x) {
return !x;
}
bool COP(bool x, bool y) {
if (x == 1 && y == 0) {
return 0;
}
return 1;
}
bool EOP(bool x, bool y) {
return !(x^y);
}
bool getTreeRes(operandParam * operandTreeHead, bool p, bool q, bool r, bool s, bool t) {
switch(operandTreeHead->operand) {
case 'p':
return p;
case 'q':
return q;
case 'r':
return r;
case 's':
return s;
case 't':
return t;
case 'N':
return NOP(getTreeRes(operandTreeHead->left, p, q, r, s, t));
case 'A':
return AOP(getTreeRes(operandTreeHead->left, p, q, r, s, t),
getTreeRes(operandTreeHead->right, p, q, r, s, t));
case 'K':
return KOP(getTreeRes(operandTreeHead->left, p, q, r, s, t),
getTreeRes(operandTreeHead->right, p, q, r, s, t));
case 'C':
return COP(getTreeRes(operandTreeHead->left, p, q, r, s, t),
getTreeRes(operandTreeHead->right, p, q, r, s, t));
case 'E':
return EOP(getTreeRes(operandTreeHead->left, p, q, r, s, t),
getTreeRes(operandTreeHead->right, p, q, r, s, t));
default:
return false;
}
}
bool checkAllOperandTreeCombination(operandParam * operandTreeHead) {
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++) {
if (!getTreeRes(operandTreeHead, p, q, r, s, t)) {
return false;
}
}
}
}
}
}
return true;
}
bool checkTautology(char * WFF) {
if (strlen(WFF) == 0) {
return false;
}
if (WFF[0] == 'p' ||
WFF[0] == 'q' ||
WFF[0] == 'r' ||
WFF[0] == 's' ||
WFF[0] == 't') {
return false;
}
operandParam * operandTreeHead;
buildOperandTree(WFF, &operandTreeHead);
// traverseOperandTree(operandTreeHead);
return checkAllOperandTreeCombination(operandTreeHead);
}
int main() {
char WFF[101];
while(1) {
scanf("%s", WFF);
if (!strcmp(WFF, "0")) {
return 0;
} else {
if (checkTautology(WFF)) {
printf("tautology\n");
} else {
printf("not\n");
}
}
}
}
C++ AC。
题本身没什么好说的, 就是根据运算符的性质(在这里的二目运算符的第一个有效参数应该是从其运算符开始以后第一个可以得到最后结果的范围内的字符串)
“构造”一个运算树, 然后遍历所有可能的value组合(这里偷懒用了5重循环,其实直接遍历 1 到 2的5次方-1 就可以, 只不过要做一个转换函数),
结合运算树求出最终值进行检验。
运算树也是一个比较典型的递归案例, 用递归可以极大的简化代码。
不过在写的过程中,感觉递归思想本身好想, 但是真正写起来, 每次递归函数要传递什么值(及当前子问题的环境变量), 已经这些值怎么又返回给上一层。
都要好好想想。
递归的性质决定了它与迭代不同(其实递归和迭代基本可以是互相转换的), 不能太依靠全局的变量, 每个子问题之间通过函数返回值和函数参数值来进行通信, 少有全局变量。
每一次递归, 环境变量都要刷新到该递归的子环境。
还要注意递归到最底层时要做相应的判断, 和给予适当的返回值。
再次感受了从思维到现实之间的鸿沟。