Find the main paradigm of propositional formula | c++ | stack, but discrete mathematics

1. Topic description

Realized function: Input the well-formed formula of the propositional formula, calculate the truth table of the formula, and output the main conjunction normal form and main disjunction normal form of the formula.

Input: well-formed formula of propositional formula

Output: principal disjunctive normal form and principal disjunctive normal form of the formula, the output form is: " mi ∨ mj ; Mi ∧ Mj", there is a space between the minimum term and the ∨ symbol, and there is a space between the maximum term and the ∧ symbol Space; the main disjunctive normal form and the main conjunctive normal form are separated by ";", and there is a space before and after ";". The main conjunctive normal form of the eternal true form is 1 , and the main disjunctive normal form of the eternal false form is 0 .

Enter a symbolic description for the formula:

! Not, equivalent to " ¬ " in written notation

& And, equivalent to " ∧ " in written symbols

| or, equivalent to "∨" in written notation

- implying connectives, equivalent to "→" in written symbols

+ Equivalent connective, equivalent to " ↔ " in written symbols

( opening bracket

) back brackets

test input expected output time limit memory limit extra process
Test case 1 display as text
  1. a&b↵
display as text
  1. m3 ; M0 ∧ M1 ∧ M2↵
unlimited 64M 0
Test case 2 display as text
  1. a|b↵
display as text
  1. m1 ∨ m2 ∨ m3 ; M0↵
unlimited 64M 0

2. Thinking analysis

        There are mainly two ways to find the principal paradigm. One is the truth table method, and the other is the equivalent algorithm. In my opinion, the former is suitable for programming solutions, and the latter is suitable for our usual handwritten calculations.

So I used the truth table method for this question.

The specific process is as follows:

1. Read in the proposition formula Formula.

2. Extract the variables that appear in it, namely p, q, r, etc. Suppose after this step we get a total of n variables.

3. Assign truth values ​​to the variables from (0,0,...,0) to (1,1,...,1) in sequence, and find the truth value of the propositional formula under each assignment.

4. Finally, output its main disjunctive normal form and main conjunctive normal form according to the truth value.

        Since certain logic operations appear in the process of calculating the truth value, you can consider using the stack method to solve the logic problems encountered. This question is mainly troublesome in the processing of characters, but the calling method of the stack is similar to the prefix to suffix conversion or the four arithmetic operations we have done in the data structure before.


I don't separate out the code one by one, because the readability is very poor, it is better to put it all. Comments I will write appropriately in the program.

        In fact, to be honest and reasonable, no one should read the large sections of code on CSDN. Either look at the idea and it’s OK, or just copy the whole paragraph, anyway, I’m like this.

#include<bits/stdc++.h> 
using namespace std;
#define N 4100
int result[N];         //result存储命题公式的真值 
string Formula;        //Formula是我们读入的命题公式
typedef struct Variant {
	char character;
	bool bool_value;
} Vrt;                 //character是变量名,bool_value是它当前的真值
Vrt v[11];             //这里是假设变元的数量不会超过11个

//operation函数的作用是进行两个真值之间的逻辑运算
void operation(bool *p1, bool p2, char op) {
	switch (op) {
		case '&': (*p1) = (*p1) && p2; break;	//与 
		case '|': (*p1) = (*p1) || p2; break;	//或 
		case '!': (*p1) = !(*p1); 	   break;	//非
		case '-': (*p1) = ((*p1)==true && p2==false) ? false : true; break;	//蕴含
		case '+': (*p1) = ((*p1)==p2) ? true : false; 				 break;	//等价 
	}
}

//TypeDe可以判断字符的种类,0表示变元,大于0表示是逻辑运算符
int TypeDe(char c) {
	if (c=='(') return 1;
	if (c==')') return 4;
	if (c=='!') return 3;
	if (c=='&' || c=='|' || c=='-' || c=='+') {
		return 2;
	}
	return 0;
}

int main(){
	
	void operation(bool*, bool, char);
	int TypeDe(char);
	
	cin >> Formula;
	int len = Formula.length(), n=0;
	
	//提取公式里的所有变元,并且存入v(v是在开头声明的)
    //为了方便,这里还把变元替换掉了
    //例如(p-(p|q))&r被我转换成了(0-(0|1))&2,这个数字0或1或2不是真值的意思,而是这个变元在v中的顺序
	{
		int i=0;
		while (i<len) {
			if ( TypeDe(Formula[i])==0 ) {
				
				if (n==0) {
					v[n].character = Formula[i];
					Formula[i] = n + '0';
					n++;
					i++;
					continue;
				}
				
				int j=0, flag=1;
				while (j<=n && flag==1) {
					if ( Formula[i]==v[j].character ) {
						flag=0; Formula[i] = j + '0';
						break;
					}
					j++;
				} 
				if (flag==1) {
					v[n].character = Formula[i];
					Formula[i] = n + '0';
					n++;
				}
				
			}
			i++;
		}
	}
	
    //为变元赋值,并且依次算出公式的真值
	for (int i=0;i<pow(2,n);i++) {
		
		//为变量赋值
		int i_extra = i;
		for (int j=0;j<n;j++) {
			v[n-j-1].bool_value = (i_extra%2==1) ? true : false;
			i_extra/=2;
			
			int k = (v[n-j-1].bool_value==true) ? 1 : 0;
		}
		 
		//建立栈,类似四则运算,如果不了解可以去看看数据结构中栈是如何处理四则运算的
		stack<char> op;       //op用来存储运算符
		stack<bool> value;    //value用来存储真值
		
		//计算过程 
		int k=0;
		while (k<len) {
			
			//如果不是运算符,直接存入value 
			if ( TypeDe(Formula[k])==0 ) {
				value.push( v[Formula[k]-'0'].bool_value );
				if (op.size() && op.top()=='!' && value.size()) {
					bool b = !value.top();
					op.pop(); value.pop();
					value.push(b);
				}
			}
			
			//否则就是运算符,分情况讨论 
			else {
				
                //如果是左括号,直接入栈即可
				if ( Formula[k]=='(' ) {
					op.push(Formula[k]);
				}

                //否则就要判断是否需要计算
				else if ( op.size() && ( (op.top()!='(' && Formula[k]==')') || (TypeDe(op.top())>=TypeDe(Formula[k])) ) ) {
				
                    //计算过程
					while ( ( (op.top()!='(' && Formula[k]==')') || (TypeDe(op.top())>=TypeDe(Formula[k])) ) && op.size() ) {
						char c = op.top();		op.pop();
						bool b = value.top(); 	value.pop();
						operation(&value.top(), b, c);
					}
					if ( Formula[k]!=')' ) {
						op.push(Formula[k]);
					}
					else {
                        //特殊情况:如果op顶部是“非”运算,而且value顶部有真值,表明这个“非”和value是一个整体。此时对这个value取反,并且弹出这个“非”。
						op.pop();
						if (op.size() && op.top()=='!') {
							bool b = !value.top();
							op.pop(); value.pop();
							value.push(b);
						}
					}
					
				}

                //不用算的话,当然直接入栈即可
				else {
					op.push(Formula[k]);
				}
				
                //特殊情况:处理连续出现的多个“非”运算符
				if (op.size() && op.top()=='!') {
					char c = '!'; op.pop();
					if (op.size() && op.top()=='!') {
						op.pop();
					}
					else op.push('!');
				}
				
			}
			k++;
		}
		
        //补刀
		if (op.size()) {
			char c = op.top();		op.pop();
			bool b = value.top(); 	value.pop();
			operation(&value.top(), b, c);
		}
        //命题公式的真值是需要被存储起来的,后面输出会用,这里result[]就是存储用的
		result[i] = (value.top()==true) ? 1 : 0;
		
	}
	
    //输出主析取范式,不要忘了永假式是输出0
	int k=0;
	for (int i=0;i<pow(2,n);i++) {
		if (result[i]==1)
			if (k==0) { k=1; cout << "m" << i; }
			else { cout << " ∨ m" << i; }
	}
	if (k==1) { cout << " ; "; }
	else { cout << 0 << " ; "; }
	
    //输出主合取范式,不要忘了重言式是输出1
	k=0;
	for (int i=0;i<pow(2,n);i++) {
		if (result[i]==0)
			if (k==0) { k=1; cout << "M" << i; }
			else { cout << " ∧ M" << i; }
	}
	if (k==0) { cout << 1; }
	cout << endl;
	
	return 0;
}

        In general, if you use the truth table method to do this question, you need to master it proficiently: use the stack to do the four arithmetic operations. This looks complicated, but it is actually simple.

        Other details, such as the processing of strings, writing a function that can perform logical operations and so on, seem simple, but there are too many details to do it.

Guess you like

Origin blog.csdn.net/m0_70241024/article/details/126999377