輸入:命題公式的合式公式
輸出:公式的主析取範式和主析取範式,輸出形式爲:“ mi ∨ mj ; Mi ∧ Mj” ,極小項和 ∨ 符號之間有一個空格,極大項和 ∧ 符號之間有一個空格;主析取範式和主合取範式之間用“ ; ”隔開,“ ; ”前後各有一個空格。 永真式的主合取範式爲 1 ,永假式的主析取範式爲 0 。
輸入公式的符號說明:
! 非,相當於書面符號中的 “ ¬ ”
& 與,相當於書面符號中的 “ ∧ ”
| 或,相當於書面符號中的 “ ∨ ”
- 蘊含聯結詞,相當於書面符號中的 “ → ”
+ 等價聯結詞,相當於書面符號中的 “ ↔ ”
( 前括號
) 後括號
方法一:
#include <cstdio>
#include <cstring>
#include <cmath>
#define N 1000
#define MAX 10000000
char s[N];
bool table[30]; //標記出現的字母
int explain[30]; //存放每個字母的值
int value[MAX];
int sum = 0;
int priority(char c)
{
switch (c)
{
case '#': return -1;
case '!': return 5;
case '&': return 4;
case '|': return 3;
case '-': return 2;
case '+': return 1;
case '(': return 0;
default: return 0;
}
}
void postfix() //將字符串處理
{
char post[N] = { '\0' };
int pp = -1;
char stack[N] = { '#' };
int ps = 0;
int len = strlen(s);
for (int i = 0; i < len; i++)
{
if (s[i] >= 'a' && s[i] <= 'z')
{
post[++pp] = s[i];
continue;
}
if (s[i] == '!' || s[i] == '&' || s[i] == '|' || s[i] == '-' || s[i] == '+')
{
while (priority(s[i]) <= priority(stack[ps]))
post[++pp] = stack[ps--];
stack[++ps] = s[i];
continue;
}
if (s[i] == '(')
{
stack[++ps] = s[i];
continue;
}
if (s[i] == ')')
{
while (stack[ps] != '(') post[++pp] = stack[ps--];
ps--;
continue;
}
}
while (ps) post[++pp] = stack[ps--];
strcpy(s, post);
int l = strlen(s);
}
void settable() //統計字母的個數
{
memset(table, 0, sizeof(table));
int len = strlen(s);
for (int i = 0; i < len; i++)
{
if (s[i] >= 'a' && s[i] < 'z')
table[s[i] - 'a'] = true;
}
for (int i = 0; i < 26; i++)
if (table[i]) sum++;
sum = pow(2, sum);
}
int btoi() //將二進制轉化爲十進制
{
int sum = 0, weight = 1;
for (int i = 25; i >= 0; i--)
if (table[i])
{
if (explain[i]) sum += weight;
weight *= 2;
}
return sum;
}
int calc(int a, int b, char c) //定義運算
{
switch (c)
{
case '&': return a * b;
case '|': if (a + b) return 1; else return 0;
case '-': if (a == 1 && b == 0) return 0; else return 1;
case '+': return !((a + b) & 1);
}
}
int work() //判斷字符串的真值
{
int stack[N], ps = -1;
int len = strlen(s);
for (int i = 0; i < len; i++)
{
if (s[i] >= 'a' && s[i] <= 'z')
{
stack[++ps] = explain[s[i] - 'a'];
continue;
}
if (s[i] == '!')
{
stack[ps] = (stack[ps] + 1) & 1;
continue;
}
int ans = calc(stack[ps - 1], stack[ps], s[i]);
stack[--ps] = ans;
}
return stack[0];
}
void assign()
{
int x = btoi();
int ans = work();
value[x] = ans;
}
void generate(char c) //從a開始,用遞歸對出現的字母進行0,1賦值
{
while (c <= 'z' && table[c - 'a'] == false) c++;
if (c > 'z')
{
assign();
return;
}
explain[c - 'a'] = 0;
generate(c + 1);
explain[c - 'a'] = 1;
generate(c + 1);
}
void output1()
{
int i = 0;
while (i < sum && !value[i]) i++;
if (i >= sum)
{
printf("0 ; ");
return;
}
printf("m%d", i);
for (i++; i < sum; i++)
if (value[i]) printf(" ∨ m%d", i);
printf(" ; ");
}
void output2()
{
int i = 0;
while (i < sum && value[i]) i++;
if (i >= sum)
{
printf("1\n");
return;
}
printf("M%d", i);
for (i++; i < sum; i++)
if (!value[i]) printf(" ∧ M%d", i);
printf("\n");
}
int main()
{
scanf("%s", s);
postfix();
settable();
memset(value, 0, sizeof(value));
memset(explain, 0, sizeof(explain));
generate('a');
output1();
output2();
return 0;
}
方法二:
#include<cstdio>
#include<cstring>
#include<cmath>
#define N 1000
using namespace std;
void panduan(int b[N],int f);//賦值函數
int tkh (char sz[N], char ccu[N], int icu[N], int h0);//分級運算函數
int fkh (char sz[N], char ccu[N], int icu[N], int h0);//主運算函數
int main()
{
int i1,i2,d=1,icu[N],kh=0,jg,j=0,h0;//icu[N]用於存放變量值,kh括號計數,jg存放結果
int bj=0,hq[N],h=0,x=0,xq[N];//hq[N]存放合取結果xq[N]存放析取結果
char sz[N],ccu[N],sz0[N],s;//sz[N]存放式子,ccu[N]存放變量,sz0[N]也是用於存放式子
hq[0]=-1;
xq[0]=-1;
gets(sz);//讀取式子
strcpy(sz0,sz);//複製式子
int l=strlen(sz);
if(l==1){
if(sz[0]>='a'&&sz[0]<='z') printf("m1 ; M0\n");
else printf("0 ; M0\n");
return 0;
}
for(i1=0;i1<strlen(sz);i1++)
{
if(sz[i1]==')' || sz[i1]=='(')//存儲括號數量
kh++;
if(sz[i1]>='a' && sz[i1]<='z' || sz[i1]>='A' && sz[i1]<='Z')
{
for(i2=0;i2<j;i2++) //判斷並儲存變量。
if(ccu[i2]==sz[i1])//去除重複變量
d=0;
if(d==1)
{
ccu[j]=sz[i1];
j++;
}
d=1;
}
}
h0=j;
for(i1=0;i1<j;i1++) ///////先將所有的變量賦值爲零。
icu[i1]=0;
jg=tkh(sz,ccu,icu,h0); //用函數求結果
if(jg==0)//結果爲0,合取加1
hq[h++]=bj;
else //否則,析取加1
xq[x++]=bj;
strcpy(sz,sz0);
for(i1=0;i1<(int)pow(2,j)-1;i1++)
{
++bj;
panduan(icu,j-1); //賦值變量
jg=tkh(sz,ccu,icu,h0);
if(jg==0)//結果爲0,合取加1
hq[h++]=bj;
else //否則,析取加1
xq[x++]=bj;
strcpy(sz,sz0); //恢復被修改的數組。
}
if(xq[0]==-1)//不存在析取範式時
printf("0 ; ");
else
{
for(i1=0;i1<x;i1++)
{
if (i1>0)//判斷並添加符號
printf(" ∨ ");
printf("m%d",xq[i1]);//輸出主析取範式
}
printf(" ; ");
}
if(hq[0]==-1)//不存在合取範式時
printf("1");
else
{
for(i1=0;i1<h;i1++)
{
if (i1>0)//判斷並添加符號
printf(" ∧ ");
printf("M%d",hq[i1]); //輸出主合取範式
}
}
printf("\n");
}
void panduan(int b[N],int f) // 二進制賦值。
{
int i;
i=f;
if(b[f]==0)//加1
b[f]=1;
else//進位
{
b[f]=0;
panduan(b,--i);
}
}
int tkh (char sz[N],char ccu[N],int icu[N],int h0)//分級運算函數
{
int i,j,h,s,kh=0,wz[N],a;
char xs1[N],ckh[N]; //xs1用來保存括號內的字符 ckh用來保存括號。
s=strlen(sz);
for(i=0;i<s;i++)
if(sz[i]=='(' || sz[i]==')')//判斷括號
{
wz[kh]=i;//存儲括號位置
ckh[kh]=sz[i];//存儲括號類型
kh++;
}
if(kh==0)
return fkh(sz,ccu,icu,h0);//如果無括號,直接運行
else
{
for(i=0;i<kh;i++)
if(ckh[i]==')')//找到第一個)
break;
for(j=wz[i-1]+1,h=0;j<wz[i];j++,h++) //存儲最內級括號中的內容
xs1[h]=sz[j];
xs1[h]='\0';
a=fkh(xs1,ccu,icu,h0);//運行最內級括號的式子,得到結果
if(a==1)//判斷並存儲結果
sz[wz[i-1]]=1;
else
sz[wz[i-1]]=-2;
for(j=wz[i-1]+1;j<s+wz[i-1]-wz[i];j++)//將括號後內容前移
sz[j]=sz[j+wz[i]-wz[i-1]];
sz[j]='\0';
return tkh(sz,ccu,icu,h0);//循環執行
}
}
int fkh(char sz[N],char ccu[N],int icu[N],int h0)//主運算函數
{
int i,h=0,j=0,j1=0,j2=0,j3=0,j4=0,j5=0,i1,i2,p1=-1,p2=-1,s;
char dt[N];
s=strlen(sz);
if(s==1)
if(sz[0]==-2)//判斷是否是最後一項
return 0;
else
return 1; //1 就是sz[0]的值、
else
{
for(i=0;i<s-j;i++) //先處理非
if(sz[i]=='!')
{
for(i1=0;i1<h0;i1++)
if(sz[i+1]==ccu[i1])//將變量賦值並給P1
p1=icu[i1];
if(sz[i+1]==-2)//如果是前運算結果的0,則P1等於0
p1=0;
if(p1==-1)//如果是數字,直接給P1
p1=sz[i+1];
dt[j+2]=!p1;//非運算
sz[i]=j+2;
j++;
p1=0;
for(i1=i+1;i1<s-j;i1++)
sz[i1]=sz[i1+1];//將後續式子前移一項
}
p1=-1;
j1=j;
for(i=0;i<s-j1-2*j2;i++) // 處理與
if(sz[i]=='&')
{
for(i1=0;i1<h0;i1++)
{
if(sz[i-1]==ccu[i1])//將變量賦值並給P1
p1=icu[i1];
if(sz[i+1]==ccu[i1])//將變量賦值並給P2
p2=icu[i1];
}
for(i2=2;i2<j+2;i2++)
{
if(sz[i-1]==i2) //如果爲前計算結果,將結果賦值並給P1
p1=dt[i2];
if(sz[i+1]==i2) //如果爲前計算結果,將結果賦值並給P2
p2=dt[i2];
}
if(sz[i-1]==-2)//如果是前運算結果的0,則P1等於0
p1=0;
if(sz[i+1]==-2)//如果是前運算結果的0,則P2等於0
p2=0;
if(p1==-1) //如果是數字,直接給P1
p1=(int)(sz[i-1]);
if(p2==-1)//如果是數字,直接給P2
p2=(int)(sz[i+1]);
dt[j+2]=p1 && p2;//與運算
sz[i-1]=j+2;
j++;
j2++;
p1=-1;
p2=-1;
for(i1=i;i1<s-j1-2*j2;i1++)//將後續式子前移兩項
sz[i1]=sz[i1+2];
i=i-1;
}
for(i=0;i<s-j1-2*j2-2*j3;i++) // 處理或。
if(sz[i]=='|')
{
for(i1=0;i1<h0;i1++)
{
if(sz[i-1]==ccu[i1])//將變量賦值並給P1
p1=icu[i1];
if(sz[i+1]==ccu[i1])//將變量賦值並給P2
p2=icu[i1];
}
for(i2=2;i2<j+2;i2++)
{
if(sz[i-1]==i2) //如果爲前計算結果,將結果賦值並給P1
p1=dt[i2];
if(sz[i+1]==i2)//如果爲前計算結果,將結果賦值並給P2
p2=dt[i2];
}
if(sz[i-1]==-2)//如果是前運算結果的0,則P1等於0
p1=0;
if(sz[i+1]==-2)//如果是前運算結果的0,則P2等於0
p2=0;
if(p1==-1)//如果是數字,直接給P1
p1=sz[i-1];
if(p2==-1)//如果是數字,直接給P2
p2=sz[i+1];
dt[j+2]=p1 || p2;//或運算
sz[i-1]=j+2;
j++;
j3++;
p1=-1;
p2=-1;
for(i1=i;i1<s-j1-2*j2-2*j3;i1++)//將後續式子前移兩項
sz[i1]=sz[i1+2];
i--;
}
for(i=0;i<s-j1-2*j2-2*j3-2*j4;i++) // 處理蘊含。
if(sz[i]=='-')
{
for(i1=0;i1<h0;i1++)
{
if(sz[i-1]==ccu[i1])//將變量賦值並給P1
p1=icu[i1];
if(sz[i+1]==ccu[i1])//將變量賦值並給P2
p2=icu[i1];
}
for(i2=2;i2<j+2;i2++)
{
if(sz[i-1]==i2) //如果爲前計算結果,將結果賦值並給P1
p1=dt[i2];
if(sz[i+1]==i2) //如果爲前計算結果,將結果賦值並給P2
p2=dt[i2];
}
if(sz[i-1]==-2)//如果是前運算結果的0,則P1等於0
p1=0;
if(sz[i+1]==-2)//如果是前運算結果的0,則P2等於0
p2=0;
if(p1==-1)//如果是數字,直接給P1
p1=sz[i-1];
if(p2==-1)//如果是數字,直接給P2
p2=sz[i+1];
dt[j+2]=!p1 || p2;//蘊含運算
sz[i-1]=j+2;
j++;
j4++;
p1=-1;
p2=-1;
for(i1=i;i1<s-j1-2*j2-2*j3-2*j4;i1++)//將後續式子前移兩項
sz[i1]=sz[i1+2];
i--;
}
for(i=0;i<s-j1-2*j2-2*j3-2*j4-2*j5;i++) // 處理等值。
if(sz[i]=='+')
{
for(i1=0;i1<h0;i1++)
{
if(sz[i-1]==ccu[i1])//將變量賦值並給P1
p1=icu[i1];
if(sz[i+1]==ccu[i1])//將變量賦值並給P2
p2=icu[i1];
}
for(i2=2;i2<j+2;i2++)
{
if(sz[i-1]==i2) //如果爲前計算結果,將結果賦值並給P1
p1=dt[i2];
if(sz[i+1]==i2) //如果爲前計算結果,將結果賦值並給P2
p2=dt[i2];
}
if(sz[i-1]==-2)//如果是前運算結果的0,則P1等於0
p1=0;
if(sz[i+1]==-2)//如果是前運算結果的0,則P2等於0
p2=0;
if(p1==-1)//如果是數字,直接給P1
p1=sz[i-1];
if(p2==-1)//如果是數字,直接給P2
p2=sz[i+1];
dt[j+2]=(!p1 || p2)&&(!p2 || p1);//等值運算
sz[i-1]=j+2;
j++;
j5++;
p1=-1;
p2=-1;
for(i1=i;i1<s-j1-2*j2-2*j3-2*j4-2*j5;i1++)//將後續式子前移兩項
sz[i1]=sz[i1+2];
i--;
}
return dt[j+1];//返回結果
}
}