【离散数学】(联结词按优先级,3个变量及以下)真值表及范式(有源码c语言,拿来就用)


实验
实验内容
编程实现用真值表法求取含三个以内变量的合式公式的主析取范式和主合取范式。
实验要求
要求:
-
从屏幕输入含三个以内变量的合式公式(其中 联结词按照从高到底的顺序出现)。
-
规范列出所输合式公式的真值表。
-
给出相应主析取和主合取范式。
[外链图片转存中…(img-KttFRYgu-1719842214597)]
具体实现
具体实现可以参考以下思路:
改造联结词
在输入联结词时就会要求用!表示否定,&表示合取,|表示析取,>表示条件,-表示双条件。
我们就设计一个函数将这些联结词改造对应的数字,以便后面switch case操作(可以省略直接在case中判断符号就行)。
//! //联结词改造函数
char* conjuction(char a[], size_t len)//len表示字符串长度
{
for (int i = 0; i < len; i++)
{
if (a[i] == '!')
a[i] = '6';
else if (a[i] == '&')
a[i] = '2';
else if (a[i] == '|')
a[i] = '3';
else if (a[i] == '>')
a[i] = '4';
else if (a[i] == '-')
a[i] = '5';
}
return a;
}
联结词计算函数
对每个联结词对应的计算方法写成函数。
//|计算函数
char or1(char a, char b)
{
if (a == '0' && b == '0')
return '0';
return '1';
}
//&计算函数
char and1(char a, char b)
{
if (a == '1' && b == '1')
return '1';
return '0';
}
//!计算函数
char dif(char a)
{
if (a == '0')
return '1';
return '0';
}
//条件判断函数
char con(char a, char b)
{
if (a == '1' && b == '0')
return '0';
else
return '1';
}
//双条件判断函数
char dou_con(char a, char b)
{
if (a == b)
return '1';
else
return '0';
}
总计算方法
我们还需要写一个函数将联结词计算方法串起来,并对合式公式进行计算。
用switch case来进行计算。
//计算函数
char count(char a[], size_t len, char b1, char b2,char b3)
{
change(a, len, b1, b2,b3);
for (int j = 0; j < len; j++)
{
if (a[j] >= '2')
{
int tem = (int)a[j] - 48;
switch (tem)
{
case 2:
a[j + 1] = and1(a[j - 1], a[j + 1]);
break;
case 3:
a[j + 1] = or1(a[j - 1], a[j + 1]);
break;
case 4:
a[j + 1] = con(a[j - 1], a[j + 1]);
break;
case 5:
a[j + 1] = dou_con(a[j - 1], a[j + 1]);
break;
case 6:
a[j + 1] = dif(a[j + 1]);
break;
default:
break;
}
}
}
return a[len - 1];
}
改命题变元值
将命题变元传来是真假分别用1 0来表示,但我写的代码只能将命题变元用PQR表示,其他不行。
//改PQ值为1 0
void change(char a[], size_t len, char b1, char b2,char b3)
{
for (int j = 0; j < len; j++)
{
if (a[j] == 'P')
a[j] = b1;
else if (a[j] == 'Q')
a[j] = b2;
else if (a[j] == 'R')
a[j] = b3;
}
}
命题变元个数判断函数
直接循环遍历然后记录出现次数就行。
//判断命题变元数量函数
int judgeNum(char a[], size_t len)
{
int numP = 0;
int numQ = 0;
int numR = 0;
int num = 0;
for (int i = 0; i < len; i++)
{
if (a[i] == 'P')
numP++;
else if (a[i] == 'Q')
numQ++;
else if (a[i] == 'R')
numR++;
}
if (numP > 0)
num++;
if (numQ > 0)
num++;
if (numR > 0)
num++;
return num;
}
打印函数
在写打印函数之前我们先来回顾一下如何根据真值表得出范式。
- 主合取范式:真值结果为假F,变元如果为真就写为否定 !P,如果为假就不取否定。
- 主析取范式:真值结果为真T,变元如果为假就写为否定!P,如果为真就不取否定。
//单变元打印
void onePrint(char a[], size_t len, char dis[], char pri[])
{
printf("该合式公式真值表如下表示:\n");
printf("P\t%s\n", a);
char b[MAX];
conjuction(a, len);
char ret;
strcpy(b, a);
ret = count(a, len, '1', '1', '1');
printf("1\t%c\n",ret);
strcpy(a, b);
ret = count(a, len, '0', '0', '0');
printf("0\t%c\n",ret);
}
//双变元打印
void twoPrint(char a[], size_t len, char dis[], char pri[])
{
printf("该合式公式真值表如下表示:\n");
printf("P\tQ\t%s\n", a);
char b[MAX];
char ret;
conjuction(a, len);
strcpy(b, a);
ret = count(a, len, '1', '1', '0');
//存储范式值
if (ret == '0')
strcat(pri, "(!P|!Q)&");
else if (ret == '1')
strcat(dis, "(P&Q)|");
printf("1\t1\t%c\n",ret);
strcpy(a, b);
ret = count(a, len, '1', '0', '0');
//存储范式值
if (ret == '0')
strcat(pri, "(!P|Q)&");
else if (ret == '1')
strcat(dis, "(P&!Q)|");
printf("1\t0\t%c\n",ret );
strcpy(a, b);
ret = count(a, len, '0', '1', '0');
//存储范式值
if (ret == '0')
strcat(pri, "(P|!Q)&");
else if (ret == '1')
strcat(dis, "(!P&Q)|");
printf("0\t1\t%c\n",ret);
strcpy(a, b);
ret = count(a, len, '0', '0', '0');
//存储范式值
if (ret == '0')
strcat(pri, "(P|Q)&");
else if (ret == '1')
strcat(dis, "(!P&!Q)|");
printf("0\t0\t%c\n",ret );
}
//三变元打印
void threePrint(char a[], size_t len, char dis[], char pri[])
{
printf("该合式公式真值表如下表示:\n");
printf("P\tQ\tR\t%s\n", a);
char b[MAX];
char ret;
conjuction(a, len);
strcpy(b, a);
ret = count(a, len, '1', '1', '1');
//计算范式
if (ret == '1')
strcat(dis, "(P&Q&R)|");
else if (ret == '0')
strcat(pri, "(!P|!Q|!R)&");
printf("1\t1\t1\t%c\n", ret);
strcpy(a, b);
//计算范式
ret = count(a, len, '1', '1', '0');
if (ret == '1')
strcat(dis, "(P&Q&!R)|");
else if (ret == '0')
strcat(pri, "(!P|!Q|R)&");
printf("1\t1\t0\t%c\n",ret );
strcpy(a, b);
//计算范式
ret = count(a, len, '1', '0', '1');
if (ret == '1')
strcat(dis, "(P&!Q&R)|");
else if (ret == '0')
strcat(pri, "(!P|Q|!R)&");
printf("1\t0\t1\t%c\n",ret);
strcpy(a, b);
//计算范式
ret = count(a, len, '1', '0', '0');
if (ret == '1')
strcat(dis, "(P&!Q&!R)|");
else if (ret == '0')
strcat(pri, "(!P|Q|R)&");
printf("1\t0\t0\t%c\n", ret);
strcpy(a, b);
//计算范式
ret = count(a, len, '0', '1', '1');
if (ret == '1')
strcat(dis, "(!P&Q&R)|");
else if (ret == '0')
strcat(pri, "(P|!Q|!R)&");
printf("0\t1\t1\t%c\n", ret);
strcpy(a, b);
//计算范式
ret = count(a, len, '0', '1', '0');
if (ret == '1')
strcat(dis, "(!P&Q&!R)|");
else if (ret == '0')
strcat(pri, "(P|!Q|R)&");
printf("0\t1\t0\t%c\n", ret);
strcpy(a, b);
//计算范式
ret = count(a, len, '0', '0', '1');
if (ret == '1')
strcat(dis, "(!P&!Q&R)|");
else if (ret == '0')
strcat(pri, "(P|Q|!R)&");
printf("0\t0\t1\t%c\n", ret);
strcpy(a, b);
//计算范式
ret = count(a, len, '0', '0', '0');
if (ret == '1')
strcat(dis, "(!P&!Q&!R)|");
else if (ret == '0')
strcat(pri, "(P|Q|R)&");
printf("0\t0\t0\t%c\n",ret);
}
//主析取范式打印
void disPrint(char dis[], size_t disLen)
{
printf("该合式公式的主析取范式:\n");
for (int i = 1; i < disLen - 1; i++)
printf("%c", dis[i]);
printf("\n");
}
//主合取范式打印
void priPrint(char pri[], size_t priLen)
{
printf("该合式公式的主合取范式:\n");
for (int i = 1; i < priLen - 1; i++)
printf("%c", pri[i]);
printf("\n");
}
主函数中调用
调用思路如下:
-
主函数中用一个字符数组来接收传来的合式公式。
-
在调用命题变元判断函数来判断有几个命题变元。
-
然后再根据命题变元个数调用对应的打印函数。
int main()
{
printf("输入不超过三种命题变元(PQR表示)的合式公式(联结词优先级从高到低):\n");
char a[MAX];
char disNorForm[MAXX] ="0";//主析取范式
char priConNorForm[MAXX]="0";//主合取范式
scanf("%s", a);
size_t len = strlen(a);
size_t disLen;
size_t priLen;
int num = judgeNum(a,len);
switch (num)
{
case 1:
onePrint(a, len,disNorForm,priConNorForm);
printf("该合式公式无主合取范式和主析取范式");
break;
case 2:
twoPrint(a, len, disNorForm, priConNorForm);
disLen = strlen(disNorForm);
disPrint(disNorForm, disLen);
priLen = strlen(priConNorForm);
priPrint(priConNorForm, priLen);
break;
case 3:
threePrint(a, len, disNorForm, priConNorForm);
disLen = strlen(disNorForm);
disPrint(disNorForm, disLen);
priLen = strlen(priConNorForm);
priPrint(priConNorForm, priLen);
break;
default:
break;
}
return 0;
}
源码
源码呈上:
#include<stdio.h>
#include<string.h>
#define MAX 20
#define MAXX 40
//联结词改造函数
char* conjuction(char a[], size_t len);
//|计算函数
char or1(char a, char b);
//&计算函数
char and1(char a, char b);
//!计算函数
char dif(char a);
//条件判断函数
char con(char a, char b);
//双条件判断函数
char dou_con(char a, char b);
//改PQ值为1 0
void change(char a[], size_t len, char b1, char b2,char b3);
//计算函数
char count(char a[], size_t len, char b1, char b2,char b3);
//判断命题变元数量函数
int judgeNum(char a[], size_t len);
//单变元打印
void onePrint(char a[], size_t len,char dis[], char pri[]);
//双变元打印
void twoPrint(char a[], size_t len, char dis[], char pri[]);
//三变元打印
void threePrint(char a[], size_t len, char dis[], char pri[]);
//主合取范式打印
void priPrint(char pri[], size_t priLen);
//主析取范式打印
void disPrint(char dis[], size_t disLen);
int main()
{
printf("输入不超过三种命题变元(PQR表示)的合式公式(联结词优先级从高到低):\n");
char a[MAX];
char disNorForm[MAXX] ="0";//主析取范式
char priConNorForm[MAXX]="0";//主合取范式
scanf("%s", a);
size_t len = strlen(a);
size_t disLen;
size_t priLen;
int num = judgeNum(a,len);
switch (num)
{
case 1:
onePrint(a, len,disNorForm,priConNorForm);
printf("该合式公式无主合取范式和主析取范式");
break;
case 2:
twoPrint(a, len, disNorForm, priConNorForm);
disLen = strlen(disNorForm);
disPrint(disNorForm, disLen);
priLen = strlen(priConNorForm);
priPrint(priConNorForm, priLen);
break;
case 3:
threePrint(a, len, disNorForm, priConNorForm);
disLen = strlen(disNorForm);
disPrint(disNorForm, disLen);
priLen = strlen(priConNorForm);
priPrint(priConNorForm, priLen);
break;
default:
break;
}
return 0;
}
//! //联结词改造函数
char* conjuction(char a[], size_t len)
{
for (int i = 0; i < len; i++)
{
if (a[i] == '!')
a[i] = '6';
else if (a[i] == '&')
a[i] = '2';
else if (a[i] == '|')
a[i] = '3';
else if (a[i] == '>')
a[i] = '4';
else if (a[i] == '-')
a[i] = '5';
}
return a;
}
//|计算函数
char or1(char a, char b)
{
if (a == '0' && b == '0')
return '0';
return '1';
}
//&计算函数
char and1(char a, char b)
{
if (a == '1' && b == '1')
return '1';
return '0';
}
//!计算函数
char dif(char a)
{
if (a == '0')
return '1';
return '0';
}
//条件判断函数
char con(char a, char b)
{
if (a == '1' && b == '0')
return '0';
else
return '1';
}
//双条件判断函数
char dou_con(char a, char b)
{
if (a == b)
return '1';
else
return '0';
}
//改PQR值为1 0
void change(char a[], size_t len, char b1, char b2,char b3)
{
for (int j = 0; j < len; j++)
{
if (a[j] == 'P')
a[j] = b1;
else if (a[j] == 'Q')
a[j] = b2;
else if (a[j] == 'R')
a[j] = b3;
}
}
//计算函数
char count(char a[], size_t len, char b1, char b2,char b3)
{
change(a, len, b1, b2,b3);
for (int j = 0; j < len; j++)
{
if (a[j] >= '2')
{
int tem = (int)a[j] - 48;
switch (tem)
{
case 2:
a[j + 1] = and1(a[j - 1], a[j + 1]);
break;
case 3:
a[j + 1] = or1(a[j - 1], a[j + 1]);
break;
case 4:
a[j + 1] = con(a[j - 1], a[j + 1]);
break;
case 5:
a[j + 1] = dou_con(a[j - 1], a[j + 1]);
break;
case 6:
a[j + 1] = dif(a[j + 1]);
break;
default:
break;
}
}
}
return a[len - 1];
}
//判断命题变元数量函数
int judgeNum(char a[], size_t len)
{
int numP = 0;
int numQ = 0;
int numR = 0;
int num = 0;
for (int i = 0; i < len; i++)
{
if (a[i] == 'P')
numP++;
else if (a[i] == 'Q')
numQ++;
else if (a[i] == 'R')
numR++;
}
if (numP > 0)
num++;
if (numQ > 0)
num++;
if (numR > 0)
num++;
return num;
}
//单变元打印
void onePrint(char a[], size_t len, char dis[], char pri[])
{
printf("该合式公式真值表如下表示:\n");
printf("P\t%s\n", a);
char b[MAX];
conjuction(a, len);
char ret;
strcpy(b, a);
ret = count(a, len, '1', '1', '1');
printf("1\t%c\n",ret);
strcpy(a, b);
ret = count(a, len, '0', '0', '0');
printf("0\t%c\n",ret);
}
//双变元打印
void twoPrint(char a[], size_t len, char dis[], char pri[])
{
printf("该合式公式真值表如下表示:\n");
printf("P\tQ\t%s\n", a);
char b[MAX];
char ret;
conjuction(a, len);
strcpy(b, a);
ret = count(a, len, '1', '1', '0');
//存储范式值
if (ret == '0')
strcat(pri, "(!P|!Q)&");
else if (ret == '1')
strcat(dis, "(P&Q)|");
printf("1\t1\t%c\n",ret);
strcpy(a, b);
ret = count(a, len, '1', '0', '0');
//存储范式值
if (ret == '0')
strcat(pri, "(!P|Q)&");
else if (ret == '1')
strcat(dis, "(P&!Q)|");
printf("1\t0\t%c\n",ret );
strcpy(a, b);
ret = count(a, len, '0', '1', '0');
//存储范式值
if (ret == '0')
strcat(pri, "(P|!Q)&");
else if (ret == '1')
strcat(dis, "(!P&Q)|");
printf("0\t1\t%c\n",ret);
strcpy(a, b);
ret = count(a, len, '0', '0', '0');
//存储范式值
if (ret == '0')
strcat(pri, "(P|Q)&");
else if (ret == '1')
strcat(dis, "(!P&!Q)|");
printf("0\t0\t%c\n",ret );
}
//三变元打印
void threePrint(char a[], size_t len, char dis[], char pri[])
{
printf("该合式公式真值表如下表示:\n");
printf("P\tQ\tR\t%s\n", a);
char b[MAX];
char ret;
conjuction(a, len);
strcpy(b, a);
ret = count(a, len, '1', '1', '1');
//计算范式
if (ret == '1')
strcat(dis, "(P&Q&R)|");
else if (ret == '0')
strcat(pri, "(!P|!Q|!R)&");
printf("1\t1\t1\t%c\n", ret);
strcpy(a, b);
//计算范式
ret = count(a, len, '1', '1', '0');
if (ret == '1')
strcat(dis, "(P&Q&!R)|");
else if (ret == '0')
strcat(pri, "(!P|!Q|R)&");
printf("1\t1\t0\t%c\n",ret );
strcpy(a, b);
//计算范式
ret = count(a, len, '1', '0', '1');
if (ret == '1')
strcat(dis, "(P&!Q&R)|");
else if (ret == '0')
strcat(pri, "(!P|Q|!R)&");
printf("1\t0\t1\t%c\n",ret);
strcpy(a, b);
//计算范式
ret = count(a, len, '1', '0', '0');
if (ret == '1')
strcat(dis, "(P&!Q&!R)|");
else if (ret == '0')
strcat(pri, "(!P|Q|R)&");
printf("1\t0\t0\t%c\n", ret);
strcpy(a, b);
//计算范式
ret = count(a, len, '0', '1', '1');
if (ret == '1')
strcat(dis, "(!P&Q&R)|");
else if (ret == '0')
strcat(pri, "(P|!Q|!R)&");
printf("0\t1\t1\t%c\n", ret);
strcpy(a, b);
//计算范式
ret = count(a, len, '0', '1', '0');
if (ret == '1')
strcat(dis, "(!P&Q&!R)|");
else if (ret == '0')
strcat(pri, "(P|!Q|R)&");
printf("0\t1\t0\t%c\n", ret);
strcpy(a, b);
//计算范式
ret = count(a, len, '0', '0', '1');
if (ret == '1')
strcat(dis, "(!P&!Q&R)|");
else if (ret == '0')
strcat(pri, "(P|Q|!R)&");
printf("0\t0\t1\t%c\n", ret);
strcpy(a, b);
//计算范式
ret = count(a, len, '0', '0', '0');
if (ret == '1')
strcat(dis, "(!P&!Q&!R)|");
else if (ret == '0')
strcat(pri, "(P|Q|R)&");
printf("0\t0\t0\t%c\n",ret);
}
//主析取范式打印
void disPrint(char dis[], size_t disLen)
{
printf("该合式公式的主析取范式:\n");
for (int i = 1; i < disLen - 1; i++)
printf("%c", dis[i]);
printf("\n");
}
//主合取范式打印
void priPrint(char pri[], size_t priLen)
{
printf("该合式公式的主合取范式:\n");
for (int i = 1; i < priLen - 1; i++)
printf("%c", pri[i]);
printf("\n");
}
写的可能有点冗杂屎山读者见谅。