题目要求:
实现功能:输入命题公式的合式公式,求出公式的真值表,并输出该公式的主合取范式和主析取范式。
输入:命题公式的合式公式
输出:公式的主析取范式和主析取范式,输出形式为:“ mi ∨ mj ; Mi ∧ Mj” ,极小项和 ∨ 符号之间有一个空格,极大项和 ∧ 符号之间有一个空格;主析取范式和主合取范式之间用“ ; ”隔开,“ ; ”前后各有一个空格。 永真式的主合取范式为 1 ,永假式的主析取范式为 0 。
输入公式的符号说明:
! 非,相当于书面符号中的 “ ¬ ”
& 与,相当于书面符号中的 “ ∧ ”
| 或,相当于书面符号中的 “ ∨ ”
- 蕴含联结词,相当于书面符号中的 “ → ”
+ 等价联结词,相当于书面符号中的 “ ↔ ”
( 前括号
) 后括号
整体思路:
1、将表达式转化成逆波兰式(后缀表达式),这个大家如果C语言课认真学的话,大一的乐学练习是有的,这个是笔者觉得最重要的一部分,只有这个部分做好才能把后续弄好。
2、根据逆波兰式,从00000....到11111.....依次遍历赋值,计算表达式的值(这个赋值过程也需要一定时间构思代码)
3、根据计算的结果,输出主范式。
全部代码:
#include<iostream>
#include<cmath>
#include<string>
#include<cstring>
using namespace std;
int op_rank(char a){
switch (a)
{
case '(':return 0;
case '+':return 1;
case '-':return 2;
case '&':return 3;
case '|':return 4;
case '!':return 5;
case ')':return 6;
}
}
bool is_in(char a,string x){
for(unsigned int i=0;i<x.size();i++){
if (x[i]==a) return true;
}
return false;
}
string post_rpn(string &input){
string stack,output;
int b=0;
for(unsigned int i=0;i<input.size();i++){
if(is_in(input[i],"()+-&|!")){
if(input[i]==')'){
while(stack[stack.size()-1]!='('){
output+=stack[stack.size()-1];
stack.erase(stack.begin()+stack.size()-1);
}
stack.erase(stack.begin()+stack.size()-1);
}
else{
while((stack.size()!=0)&&op_rank((stack[stack.size()-1]))>=op_rank(input[i])&&input[i]!='('){
output+=stack[stack.size()-1];
stack.erase(stack.begin()+stack.size()-1);
}
stack+=input[i];
}
}
else output+=input[i];
}
while(stack.size()!=0) {
output+=stack[stack.size()-1];
stack.erase(stack.begin()+stack.size()-1);
}
return output;
}
string how_mang_elements(string a){
string b="";
for(unsigned int i=0;i<a.size();i++){
if(a[i]>='a'&&a[i]<='z'&&!is_in(a[i],b)){
b+=a[i];
}
}
for(unsigned int x=0;x<b.size();x++){
for(unsigned int y=0;y<b.size()-x-1;y++){
if(a[y]>a[y+1]){
char c=a[y];
a[y]=a[y+1];
a[y+1]=c;
}
}
}
return b;
}
int cal(int a,int b,char c){
if(c=='+'){
if(a==b) return 1;
else return 0;
}
else if(c=='-'){
if(a==1&&b==0) return 0;
else return 1;
}
else if(c=='|'){
if(a+b>=1) return 1;
else return 0;
}
else if(c=='&') {return a*b;}
else if(c=='!') {
if(a==1) return 0;
else return 1;
}
}
int calculate(string a){
while(a.size()>1){
for(unsigned int i=0;i<a.size();i++){
if(is_in(a[i],"+|&-!")){
if(a[i]!='!'){
a[i-2]=char(cal(int(a[i-2]-'0'),int(a[i-1]-'0'),a[i])+'0');
a.erase(a.begin()+i-1);
a.erase(a.begin()+i-1);
break;
}
else{
a[i-1]=char(cal(int(a[i-1]-'0'),0,a[i])+'0');
a.erase(a.begin()+i);
break;
}
}
}
}
return int(a[0]-'0');
}
bool is_in2(int a,int *x,int d){
for(int i=0;i<d;i++){
if (x[i]==a) return true;
}
return false;
}
bool is_in3(int n,int i0,int *x,int d){
for(int i=i0+1;i<n;i++){
if(!is_in2(i,x,d)) return true;
}
return false;
}
void PRINT(int *n,string number,int d){
if(d==0){
cout<<"0"<<" ; ";
}
for(int i=0;i<d;i++){
if((i!=d-1)&&is_in2(n[i],n,d)){
cout<<"m"<<n[i]<<" ∨ ";
}
else if(is_in2(n[i],n,d)){
cout<<"m"<<n[i]<<" ; ";
}
}
for(int i=0;i<pow(2,number.size());i++){
if(!is_in3(pow(2,number.size()),-1,n,d)){
cout<<"1"<<endl;
break;
}
else {if(!is_in2(i,n,d)&&is_in3(pow(2,number.size()),i,n,d)){
cout<<"M"<<i<<" ∧ ";
}
else if(!is_in2(i,n,d)){
cout<<"M"<<i<<endl;
}}
}
}
int where_is_element(string number0,char a){
for(int i=0;i<number0.size();i++){
if(number0[i]==a) return i;
}
}
void bianli(string number,string output2){
string a="",number0=number;
int c[500],d=0;
for(int i=0;i<pow(2,number.size());i++){
int p=i;
a="";
while(p!=0){
a=char(p%2+'0')+a;
p=p>>1;
}
int b=0;
for(unsigned int j=0;j<number.size();j++){
if(a.size()<number.size()-j) number[j]='0';
else number[j]=a[b++];
}
string output=output2;
for(unsigned int i=0;i<output.size();i++){
if(output[i]>='a'&&output[i]<='z') {
output[i]=number[where_is_element(number0,output[i])];
}
}
if(calculate(output)==1) {c[d++]=i;}
}
PRINT(c,number,d);
}
int main(void){
string input;
cin>>input;
bianli(how_mang_elements(post_rpn(input)),post_rpn(input));
}
代码较为简单,请读者自行分析。