[POJ 3295]Tautology[构造][DFS]

题目链接: [POJ 3295]Tautology[构造][DFS]

题意分析:

给出一个表达式,问:这个表达式是否是永真的?是的话,输出“tautology”,否则“not”。

其中变量最多有5个,代表字母为:p q r s t

大写字母:K-与,A-或,N-否,C-蕴含,E-相等

解题思路:

变量最多五个,那么就把所有情况都枚举一遍。解析表达式,使用dfs进行扫描,直到扫描到小写字母为止。另外要注意单目和双目运算符分类讨论下。

个人感受:

dfs的返回值社会其真值的返回值,那么dfs到达的位置信息怎么记录呢?就是说双目运算符,计算完左边的参数,那么右边的起点怎么记录呢?引用是个不错的选择!

具体代码如下:

#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iomanip>
#include<iostream>
#include<map>
using namespace std;

const int MAXN = 1e3;

bool num[5];
char op[MAXN];
map<char, int> id; // 变量值映射

int dfs(int &pos) {
    char cur = op[pos];
    if (islower(cur)) return num[id[cur]];

    if (cur == 'N') {
        ++pos;
        return !dfs(pos);
    }
    else {
        ++pos;
        int lson = dfs(pos);
        ++pos;
        int rson = dfs(pos);

        if (cur == 'K') return (lson & rson);
        else if (cur == 'A') return (lson | rson);
        else if (cur == 'E') return (lson == rson);
        else return !(lson == 1 && rson == 0);
    }
}

int main()
{
    id['p'] = 0, id['q'] = 1, id['r'] = 2, id['s'] = 3, id['t'] = 4;

    while (~scanf("%s", op)) {
        if (op[0] == '0') break;
        bool flag = 1;
        for (int i = 0; i < 1 << 5; ++i) { // 枚举所有情况
            for (int j = 0; j < 5; ++j) {
                num[j] = i & (1 << j);
            }
            int pos = 0;
            if (!dfs(pos)) { // 只要一找到假的情况,就可以break了
                flag = 0;
                break;
            }
        }

        if (flag) printf("tautology\n");
        else printf("not\n");
    }
    return 0;
}


你可能感兴趣的:(DFS,构造)