離散數學—求主範式

輸入:命題公式的合式公式

輸出:公式的主析取範式和主析取範式,輸出形式爲:“ 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];//返回結果

    }

}


發佈了42 篇原創文章 · 獲贊 4 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章