【问题描述】
请根据给定的命题公式,计算其真值为T的小项,列出主析取范式,并输出结果。
【输入形式】
输入一个字符串(字符串长度<=50)形式的命题公式,以回车表示输入结束。其中的命题公式为仅包含原子命题、联结词和括号的合式公式。联结词仅包含下述5中联结词:
1、否定,表示为“!”
2、合取,表示为“*”
3、析取,表示为“|”
4、条件,表示为“-”
5、双条件,表示为“=”
例如:
(P-Q)-R
注意:输入符号均采用英文输入。
【输出形式】
输出一个以单个空格分隔的字符串,字符串中各项分别对应主析取范式中小项的序号。
如(P-Q)- R对应的小项为
则输出1 3 4 5 7
注意:其中的原子命题按字母表排序。
【样例输入】
(P-Q)-R
【样例输出】
1 3 4 5 7
算法分析
显然将给出的公式中提取出它的n个不同命题变元,显然每个变元的赋值非真即假,而他们的组合情况恰有2^n种情况,故而可用二进制的形式来模拟,对n个变元进行赋值。在二进制赋值中我们采用模拟二进制过程的算法,从0000开始,从最后一位开始加1,直至最后结果为1111;显然这就包含了2 n种情况。
具体实现代码如下
void truth(int times)
{
int i = argument.size() - 1;
while (times)
{
a[i] = (times & 1);
times >>= 1;
--i;
}
int len = argument.size();
for (i = 0; i < len; ++i)
mp[argument[i]] = a[i];
// display
for (int i = 0; i < len; ++i)
cout << a[i] << '\t';
cout << endl;
}
再者,显然该命题公式就是一个中缀表达式的式子,故而在有了对命题变元的赋值后,我们可以采用处理计算中缀表达式的值的算法来做。首先最一般的算法就是写一个模拟过程,采用栈存储,利用运算符的优先级大小关系进行运算。但值得注意的是,中缀表达式可以处理成二叉表达树的形式,如下图
显然,运算符都将会是分支结点,而命题变元将会是叶子结点,因此在构建出二叉表达树后,我们采用后序遍历进行运算直至根节点,便可得出一组赋值的情况,而二叉树的建立也是采用栈的存储,利用优先级关系进行建树。
具体解释将在代码中给出。
/*
* @Author: csc
* @Date: 2020-12-08 14:12:16
* @LastEditTime: 2020-12-11 00:02:42
* @LastEditors: Please set LastEditors
* @Description: In User Settings Edit
* @FilePath: \code\data structure\ls_tree.cpp
*/
#include <iostream>
#include <algorithm>
#include <string>
#include <string.h>
#include <cmath>
#include <map>
#include <vector>
#include <stack>
using namespace std;
// 联结词优先 ! * | - = 高到低
unsigned char prior[7][7] = {
//比较大小关系
'>', '<', '<', '<', '<', '<', '>',
'>', '>', '<', '<', '<', '<', '>',
'>', '>', '>', '<', '<', '<', '>',
'>', '>', '>', '>', '<', '<', '>',
'>', '>', '>', '>', '<', '>', '>',
'<', '<', '<', '<', '<', '<', '=',
'>', '>', '>', '>', '>', ' ', '>', };
char opset[7] = {
'=', '-', '/', '*', '!', '(', ')'};
/**
* @description: 假设有两个变量x,y;不妨设x为先出现的变量,则它对应的
* 应为行数,y则对应列数,此时便可列优先级方阵,其中‘<'代表x的优先级小于y
*/
int returnOpOrd(char op, char *TestOp) // 返回运算符对应的下标
{
int i;
for (i = 0; i < 7; i++)
{
if (op == TestOp[