用C语言求解命题公式的主合取范式和主析取范式

我最爱的冯老师在离散课上出了一个附加题。
为了能够加更多的学分也是出于自己的好奇,我决定尝试一下。
思路:二进制枚举+逆波兰表达式

#include
#include
#define T 1
#define F 0

struct Stack{
     
    int top;
    char arr[80];
}number={
     -1},symbol={
     -1};
//number储存后缀表达式结果
//symbol用来保存 

int book[26];
int num=0;
int alphabet_true_false[26];
int enum_result[80];
char str_copy[80];
 
void scan_string(char str[]){
     
	//输入小写字符
	//例如!(p|q)>(q&!r|(r>p)) 
	int i;
    gets(str);
    strcpy(str_copy,str);
    int len=strlen(str);
    for(i=0;i<len;i++){
     
        if(str[i]>='a'&&str[i]<='z'){
     
            if(book[str[i]-'a']==0){
      
				book[str[i]-'a']=1;    
				++num; 
			} 
    	}
        switch(str[i]){
     
            case '!':str[i]=')'+5;break;
            case '&':str[i]=')'+4;break;
            case '|':str[i]=')'+3;break;
            case '>':str[i]=')'+2;break;
            case '=':str[i]=')'+1;break;
        }        
    }
}

void reverse_polish(char s[]){
     
    int i,len=strlen(s);
    for(i=0;i<len;i++){
     
        if(s[i]>='a'&&s[i]<='z'){
     
            number.arr[++number.top]=s[i];          
        }else if(s[i]>')'&&s[i]<=5+')'){
     
            if(symbol.top==-1||symbol.arr[symbol.top]==')'){
     
                ++symbol.top;
                symbol.arr[symbol.top]=s[i];
            }else if(s[i]>=symbol.arr[symbol.top]){
     
                ++symbol.top;
                symbol.arr[symbol.top]=s[i];
            }else{
     
                while(symbol.top!=-1&&s[i]<symbol.arr[symbol.top]){
     
                    ++number.top;
                    number.arr[number.top]=symbol.arr[symbol.top];
                    --symbol.top;
                }
                --i;
            }
        }
		else if(s[i]=='('||s[i]==')'){
     
		    if(s[i]=='('){
     
                ++symbol.top;
                symbol.arr[symbol.top]=s[i];
            }else{
     
                while(symbol.arr[symbol.top]!='('){
     
                    ++number.top;
                    number.arr[number.top]=symbol.arr[symbol.top];
                    --symbol.top;              
                }
                if(symbol.top!=-1)--symbol.top;
            }
        }       
    }
    while(symbol.top!=-1){
     
        ++number.top;
        number.arr[number.top]=symbol.arr[symbol.top];
        --symbol.top;                                
    }
}

int check(int num){
     
	struct Stack ans={
     -1};
	int i,k=0,len=0,temp;
	for(i=0;i<26;i++){
     
		if(book[i]){
     
			++len;
			alphabet_true_false[i]=enum_result[k++];
		}
	}
	for(i=0;i<=number.top;i++){
     
		if(number.arr[i]>='a'&&number.arr[i]<='z'){
     
			++ans.top;
			ans.arr[ans.top]=alphabet_true_false[number.arr[i]-'a'];
		}else{
     
			switch(number.arr[i]){
     
				case '.':
					ans.arr[ans.top]=!ans.arr[ans.top];
					break;
				case '-':
					ans.arr[ans.top-1]=ans.arr[ans.top-1]&ans.arr[ans.top];
					--ans.top;
					break;
				case ',':
					ans.arr[ans.top-1]=ans.arr[ans.top-1]|ans.arr[ans.top];
					--ans.top;
					break;
				case '+':
					ans.arr[ans.top-1]=!ans.arr[ans.top-1]|ans.arr[ans.top];
					--ans.top;
					break;
				case '*':
					ans.arr[ans.top-1]=
									 (!ans.arr[ans.top-1]|ans.arr[ans.top])
									&(!ans.arr[ans.top]|ans.arr[ans.top-1]);
					--ans.top;
					break;
			}
		}
	}
	printf("%4d\n",ans.arr[0]); 
	return ans.arr[0];
}

void binary_enumeration(int num){
     
	//二进制枚举 2^num次 遍历所有情况 
	int i,j,conjunction_top=-1,disjunction_top=-1;
	int result_conjunction[80]={
     0},result_disjunction[80]={
     0};
	//我要配的上她
	for(i=0;i<26;i++)
        if(book[i])printf("%4c|",i+'a');
	putchar(' '),puts(str_copy);
	
	for(i=0;i<(1<<num);i++){
     
		memset(enum_result,0,num);
		for(j=0;j<num;j++){
     
			if(i&(1<<(num-j-1))){
     
				enum_result[j]=T;
			}else{
     
				enum_result[j]=F;
			}
			printf("%4d|",enum_result[j]);
		}
		if(check(num)){
     
			result_disjunction[++disjunction_top]=i;//主析取十进制下标 
		}else{
     
			result_conjunction[++conjunction_top]=i;//主合取十进制下标 
		}
	}
	puts("\n主析取范式为:");
	for(i=0;i<=disjunction_top;i++){
     
		printf("m%d%s",result_disjunction[i],i^disjunction_top?"&":"");
	}
	puts("\n主合取范式为:");
	for(i=0;i<=conjunction_top;i++){
     
		printf("M%d%s",result_conjunction[i],i^conjunction_top?"|":"");
	}
}

void show(char str[]){
     
	int i; 
	puts("\n后缀表达式为:");
    for(i=0;i<=number.top;i++){
     
    	switch(number.arr[i]){
     
            case ')'+5:number.arr[i]='!';break;
            case ')'+4:number.arr[i]='&';break;
            case ')'+3:number.arr[i]='|';break;
            case ')'+2:number.arr[i]='>';break;
            case ')'+1:number.arr[i]='=';break;
        } 
        printf("%c",number.arr[i]);
    }
    
    puts("\n使用的命题变项:");
    for(i=0;i<26;i++)
        if(book[i])printf("%c ",i+'a');
}

/*
           优先级
非  :!      5
合取:&       4
析取:|       3
蕴涵:>       2
等价:=       1
*/

int main()
{
     
    int i=0;
    char str[80];
    scan_string(str);//输入小写字符
	reverse_polish(str);//逆波兰表达式 去括号 
    binary_enumeration(num);
	show(str);
    return 0;
}

大一,寒假时为了蓝桥杯学了不少算法和数据结构的知识。
写了将近4个小时。又复习了一遍后缀表达式。
算法方面没有什么不理解的地方,大部分时间都是细节上的错误,
比如

for(i=0;i<=number.top;i++){
     
	switch(number.arr[i]){
     
	...
	}
}

写成

for(i=0;i<=number.top;i++){
     
	switch(number.arr[number.top]){
     //循环的是i,我却循环成了栈顶元素。这个地方卡了差不多一个小时。可能是因为太晚了脑子有点糊涂
	...
	}
}

程序跑通了调的没bug了之后拿给老师看,老师理所当然的给出了肯定的评价;
就是不知道她什么时候能把我这个分给加上。

以下是运行结果:
用C语言求解命题公式的主合取范式和主析取范式_第1张图片
为了配的上我心中的那个执念
lonely but only study
lonely but only suppress

你可能感兴趣的:(笔记,算法,数学)