大一菜雞肝了近兩個小時的成果,用於計算真值表;
拿來水一篇博客(並不);
代碼中比較重要的兩部分是原式向后綴式的轉換,遍歷所有原子命題的可能取值;
具體的細節看代碼吧,盡量添加了注釋;
#include<bits/stdc++.h>
using namespace std;
const int maxn = 105;
const int maxstr = 1e5 + 10;
char s[maxstr],str[maxstr],Vstr[maxn];//依次為原式,后綴式,存放原子命題的符號
bool var[maxn];//不同原子命題的真值
map<char,int>v;//儲存原子命題對應的編號
void Print_true(bool b){//打印bool對應的真值符號
if(b) printf("T\t");
else printf("F\t");
}
int Priority(char c){//返回運算符的優先級
int p;
switch (c) {
case '!': p = 5; break;
case '&': p = 4; break;
case '|': p = 3; break;
case '-': p = 2; break;
case '=': p = 1; break;
default : p = 0; break;
}
return p;
}
bool ToPostfix(){//原式轉化為后綴表達式
int cnt = 0;
int len = strlen(s);
stack<char>ope;
for(int i=0; i<len; i++){
if(s[i] == '('){
ope.push(s[i]);
}
else if(s[i] == ')'){
if(ope.empty()) return false;
while(ope.top() != '('){
str[cnt++] = ope.top();
ope.pop();
if(ope.empty()) return false;
}
ope.pop();
}
else if(Priority(s[i]) == 0){
str[cnt++] = s[i];
}
else {
if(ope.empty()){
ope.push(s[i]);
}
else {
if(Priority(s[i]) > Priority(ope.top())){
ope.push(s[i]);
}
else{
while(!ope.empty() && ope.top() != '(' && Priority(s[i]) <= Priority(ope.top())) {
str[cnt++] = ope.top();
ope.pop();
}
ope.push(s[i]);
}
}
}
}
while(!ope.empty()){
str[cnt++] = ope.top();
ope.pop();
}
str[cnt] = 0;
return true;
}
bool Calculate(bool a, bool b, char ope){//進行真值的運算
bool ans;
if(ope == '&'){
if(a == true && b == true) ans = true;
else ans = false;
}
else if(ope == '|'){
if(a == true || b == true) ans = true;
else ans = false;
}
else if(ope == '-'){
if(a == true && b == false) ans = false;
else ans = true;
}
else if(ope == '='){
if(a == b) ans = true;
else ans = false;
}
return ans;
}
void init_var(int n, int sum){//對var數組初始化
while(sum>0){
bool x = sum%2;
var[n--] = x;
sum /= 2;
}
do{
var[n--] = false;
}while(n > 0);
}
bool Result(){//對后綴式進行計算
stack<bool>res;
int len = strlen(str);
for(int i=0; i<len; i++){
if(str[i] == '!'){
if(res.empty()){
printf("計算出現異常!\n");
}
else {
bool f = res.top();
// printf("text = %d\n",f);
res.pop();
res.push(!f);
}
}
else if(Priority(str[i])){
bool a,b;
if(res.empty()) printf("計算出現異常!\n");
else {
b = res.top();
res.pop();
}
if(res.empty()) printf("計算出現異常!\n");
else {
a = res.top();
res.pop();
}
bool ans = Calculate(a, b, str[i]);
res.push(ans);
}
else {
res.push(var[v[str[i]]]);
}
}
return res.top();
}
void Print_Out(){//打印提示語
printf("您好,歡迎使用離散數學真值表計算V1.2版本。\n");
printf("使用說明:數據為多組輸入,每組一行,直接輸入命題公式即可。\n");
printf("注:命題變元必須使用小寫或大寫字母表示。\n");
printf("聯結詞說明(英文符號): 非:! 合取:& 析取:|(邏輯或) 條件:-(負號) 雙條件:=\n");
}
void NumOfVar(int &n){//提取命題公式中的變元
int len = strlen(s);
bool asi[200];
memset(asi, false, sizeof(asi));
for(int i=0; i<len; i++){
asi[s[i]] = true;
}
n = 0;
for(int i='A'; i<='Z'; i++){
if(asi[i]){
Vstr[++n] = i;
v[i] = n;
}
}
for(int i='a'; i<='z'; i++){
if(asi[i]){
Vstr[++n] = i;
v[i] = n;
}
}
}
int main(){
int n,cnt=0;
Print_Out();
printf("\n請輸入第%d組:\n",++cnt);
while(~scanf("%s",s)){
v.clear();
NumOfVar(n);
if(ToPostfix()==false){
printf("您輸入的原式錯誤\n");
}
else {
//標題欄的輸出
for(int i=1; i<=n; i++){
printf("%c\t",Vstr[i]);
}
printf("%s\n",s);
//打印各部分真值
int m = pow(2,n);
for(int i=0; i<m; i++){
init_var(n, i);
for(int j=1; j<=n; j++){
Print_true(var[j]);
}
bool ans = Result();
Print_true(ans);
printf("\n");
}
printf("\n");
printf("請輸入第%d組:\n",++cnt);
}
}
return 0;
}