离散数学实验报告.docx
《离散数学实验报告.docx》由会员分享,可在线阅读,更多相关《离散数学实验报告.docx(38页珍藏版)》请在冰豆网上搜索。
离散数学实验报告
实验一
一实验内容(选作AB类)
1.从键盘输入两个命题变元P和Q的真值,求它们的合取、析取、条件和双条件的真值。
(A)
2.求任意一个命题公式的真值表(B,并根据真值表求主范式(C))
二实验目的
熟悉掌握命题逻辑中的联接词、真值表、主范式等,进一步能用它们来解决实际问题。
三实验环境
C语言编程环境实现。
四1、实现A类算法原理
根据析取、合取的定义可用简单的算术运算求出结果,并将结果转换成逻辑值。
同样根据等价关系可将条件式及双条件式转换成析取和合取的运算。
此题较简单
2、实现BC类算法原理
算法逻辑如下:
(1)将二进制加法模拟器赋初值0
(2)计算模拟器中所对应的一组真值指派下合式公式的真值。
(3)输出真值表中对应于模拟器所给出的一组真值指派及这组真值指派所对应的一行真值。
(4)产生下一个二进制数值,若该数值等于2n-1,则结束,否则转
(2)。
(5)在进行表达式求值的时候,可先将带括号的中缀表达式利用栈结构转换为不带括号的后缀表达式(逆波兰式),然后进行计算。
具体方法请参考数据结构中有关“栈”的知识。
五实验数据及结果分析
1(A类)
2(B类)
从实验结果可以看到:
当输入的数据不是逻辑值时须重新输入,当输入符合逻辑值才能继续下去。
从结果来看完全正确,由于界面有限没有把所有结果都贴上,根据运行情况来看没有错误
六 源程序清单
1(A类)
#include
//#include
main()
{
while
(1) //输入符合逻辑值的命题变元P值
{
inta,b,c,d,e,f,g;
while
(1)
{
printf("\ninputthelogicvalueofthemintiP(0or1):
");
scanf("%d",&a);
if((a!
=0)&&(a!
=1))
{
printf("youhaveinputthewrongvalue,pleasereinput");
}
elsebreak;
}
while
(1) //输入符合逻辑值的命题变元Q值
{
printf("\ninputthelogicvalueofthemintiQ(0or1):
");
scanf("%d",&b);
if(b!
=0&&b!
=1)
printf("youhaveinputthewrongvalue,pleasereinput");
elsebreak;
}
c=a*b; //合取
d=a+b; //析取
e=(!
a)+b; //条件式
f=a*b+(!
a)*(!
b);//双条件式
if(c==0)//化为逻辑值
c=0;
else
c=1;
if(d==0)
d=0;
else
d=1;
if(e=0)
e=0;
else
e=1;
if(f==0)
f=0;
else
f=1;
printf("\nthelogicvalueofhequ:
%d\nthelogicvalueofxiqu:
%d\nthelogicvalueoftiaojian:
%d\nthelogicvalueofshuangtiaojian:
%d\n",c,d,e,f);
printf("doyouwanttocontinue?
input'y'continue");
g=getch
();
{
if(g=='y')
;
elsebreak;
}
}
}
2(B类)
#include
#include
#include
#include
typedefstructNode//二叉树节点结构体
{
chardata;//存节点字符
structNode*leftchild;//左孩子指针
structNode*rightchild;//右孩子指针
inttemp;//判断该节点前是否有特别的字符类型
}BeTreeNode;
/*typedefstruct
{
charstack[30];
inttop;
}SeqStack;//账的结构体*/
voidprint_char(BeTreeNode*root);
voidprints(BeTreeNode*p);
charstr[30];//输入的字符串
charS[16];//仅存是字母的字符串
intw,length,x=1;//分辨取哪一种真值赋值
//SeqStackmystack;//定义一个栈
BeTreeNode*pt[30];//定义指针数组
int**S_num;//二维数组存真值的多种赋值情况
intL=0;
/*voidStackInitiate(SeqStack*S)//初始化
{
S->top=0;
}
intStackNotEmpty(SeqStackS)//非空否
{
if(S.top<=0)return0;
elsereturn1;
}
intStackPush(SeqStack*S,charx)//入栈
{
if(S->top>=16)
{
printf("堆栈已满无法插入!
\n");
return0;
}
else
{
S->stack[S->top]=x;
S->top++;
return1;
}
}
*/
BeTreeNode*MakeTree(inta,intb)//建立二叉树
{
inti,j=0,k=0,a1[10],b1[10];
intL=0;
BeTreeNode*p[10];
BeTreeNode*pp,*sign=NULL;
for(i=a;i<=b;i++)//若有括号的先渐入括号的最内层
{
if(str[i]=='(')
{
//if(mystack.top==0)
if(L==0)
a1[j]=i;
L++;
}
if(str[i]==')')
{
L--;
if(L==0){b1[j]=i;p[j]=MakeTree(a1[j]+1,b1[j]-1);j++;}
}
}
j=0;
for(i=a;i<=b;i++,k++)//用指针来存储二叉树的每个节点
{
if(str[i]=='!
')
{
if(str[i+1]=='(')
{pt[k]=p[j];
pt[k]->temp=2;
i=b1[j];
j=j+1;
}
else
{pt[k]=(BeTreeNode*)malloc(sizeof(BeTreeNode));
pt[k]->data=str[i+1];
pt[k]->leftchild=NULL;
pt[k]->rightchild=NULL;
pt[k]->temp=-1;
i=i+1;
}
}
elseif(str[i]=='(')
{
pt[k]=p[j];
pt[k]->temp=1;
i=b1[j];
j=j+1;
}
else
{pt[k]=(BeTreeNode*)malloc(sizeof(BeTreeNode));
pt[k]->data=str[i];
pt[k]->leftchild=NULL;
pt[k]->rightchild=NULL;
pt[k]->temp=0;
}
}
pp=pt[0];
for(i=1;i{
if(pt[i]->data=='|')
{pt[i]->leftchild=pp;
pt[i]->rightchild=pt[i+1];
pp=pt[i];
}
else
{
if(sign!
=NULL)
{pt[i]->leftchild=sign;
sign->rightchild=pp;
pp=pt[i];
sign=NULL;
}
else
{pt[i]->leftchild=pp;
pp=pt[i];
}
if(i+2{
if(pt[i+2]->data=='|')
{pp=pt[i+1];
sign=pt[i];
}
else
{
pp->rightchild=pt[i+1];
}
}
}
}
if(sign!
=NULL)
{sign->rightchild=pp;pp=sign;}
elsepp->rightchild=pt[k-1];
returnpp;
}
voidprints(BeTreeNode*p)//根据各个节点前的标记符的赋值确定应该要输出哪种字符
{
if(p->temp==2)
{printf("!
(");
print_char(p);
printf(")");
}
elseif(p->temp==1)
{printf("(");
print_char(p);
printf(")");
}
elseif(p->temp==-1)
{printf("!
");
print_char(p);
}
else
print_char(p);
}
voidprint_char(BeTreeNode*root)//输出某个节点下的树
{
if(root->leftchild==NULL&&root->rightchild==NULL)
{
printf("%c",root->data);
}
else
{
prints(root->leftchild);
printf("%c",root->data);
prints(root->rightchild);
}
}
voidprint(BeTreeNode*root)//利用二重循环来进行从最内层的子树开始输出,直到输出整棵树
{
if(root->leftchild->leftchild!
=NULL)
print(root->leftchild);
if(root->rightchild->leftchild!
=NULL)
print(root->rightchild);
if(root->leftchild->temp==-1)
printf("!
%c",root->leftchild->data);
if(root->rightchild->temp==-1)
printf("!
%c",root->rightchild->data);
print_char(root);
if(root->temp==2)
{printf("");prints(root);}
printf("");
}
intnumre(charc)//输出叶节点
{
inti;
for(i=0;i{
if(S[i]==c)returnS_num[w][i];
}
}
intJudge(intnum1,charc,intnum2)//判断最简单的表达式的返回值
{
if(c=='&')
{
if(num1==num2&&num1==1)return1;
elsereturn0;
}
if(c=='|')
{
if(num1==num2&&num1==0)return0;
elsereturn1;
}
}
intprint_num(BeTreeNode*root)//从最内层开始输出返回值
{
intnum1,num2,num,i;
charc;
if(root->leftchild==NULL&&root->rightchild==NULL)
{
num=numre(root->data);
}
else
{
num1=print_num(root->leftchild);
c=root->data;
num2=print_num(root->rightchild);
if((root->leftchild->temp==2)||(root->leftchild->temp==-1))
{for(i=0;iprintf("");
printf("%d",num1);
}
if((root->rightchild->temp==2)||(root->rightchild->temp==-1))
{for(i=0;iprintf("");
printf("%d",num2);
}
num=Judge(num1,c,num2);
for(i=0;iprintf("");
printf("%d",num);
x=x+3;
}
if((root->temp==2)||(root->temp==-1))
{
if(num==1)num=0;
elsenum=1;
}
returnnum;
}
intfac(intt)//计算出2的n次方的结果
{
if(t==0)return1;
if(t==1)return2;
return2*fac(t-1);
}
voidS_numf(intn)//开辟一个二维数组存储真值表的各种赋值情况
{
introw,col,i,j,k,p;
row=fac(n);
col=n;
S_num=(int*)malloc(sizeof(int)*row);
for(i=0;i{
S_num[i]=(int*)malloc(sizeof(int)*col);
}
for(i=0;ifor(j=0;j
S_num[i][j]=0;
for(i=0;i
for(k=0,j=fac(i);k{for(p=col-1;p>col-1-i;p--)
S_num[j][p]=S_num[k][p];
S_num[j][p]=1;
}
}
main()
{
inti,j,LEN,t=0,temp=1;
BeTreeNode*root;//定义根节点
//StackInitiate(&mystack);
printf("请输入一个符合命题公式(仅支持非'!
',析取'|',合取'&',优先级:
!
|,&)\n:
");
gets(str);
LEN=strlen(str);
for(i=0;i{for(j=0;jif(S[j]==str[i])temp=0;
if((str[i]>='a'&&str[i]<='z'||str[i]>='A'&&str[i]<='Z')&&temp){S[j]=str[i];t++;}
temp=1;
}
length=strlen(S);
S_numf(length);
root=MakeTree(0,LEN-1);
printf("该复合命题公式的真值表是:
\n");
for(i=0;iprintf("%c",S[i]);
print(root);
printf("\n");
for(w=0;w{
for(i=0;iprintf("%d",S_num[w][i]);
print_num(root);
printf("\n");
x=1;
}
}
七 收获与体会
通过这次实验使我了解了一些数理逻辑问题可以通过用计算机编程的方法来解决,一些定理的证明同样也可以用计算机通过将命题符号化来编程解决。
由于计算机运行速度很快,而数理逻辑值只有0、1值,只要用程序合理的表述问题,那么就能将问题解答出来。
再次,它提高了我的计算机编程能力,使我感觉到了编程的乐趣,提供给我无穷的继续学习编程语言的动力。
实验二
一实验内容(三选一)(选作C类)
1.求有限集上给定关系的自反、对称和传递闭包。
(有两种求解方法,只做一种为A,两种都做为B)
2.求有限集上等价关系的数目。
(有两种求解方法,只做一种为A,两种都做为B)
3.求解商集,输入集合和等价关系,求相应的商集。
(C)
二实验目的
掌握关系的概念与性质,基本的关系运算,关系的各种闭包的求法。
理解等价类的概念,掌握等价类的求解方法。
三实验环境
C语言编程环境实现。
四 实验原理和实现过程
求解商集,输入集合和等价关系,求相应的商集
商集即等价类构成的集合,要求商集,首先需要判断输入的关系是否为等价关系,否则没有商集。
确定集合A={a1,a2,a3,…,an}关于R的等价类的算法如下:
(1)令A中每一个元素自成一个子集,如A1={a1},A2={a2},…,An={an}
(2)对R中每个二元组,判定x和y所属子集。
假设x属于Ai,y属于Aj,若Ai<>Aj,则将Ai并入Aj,并置Ai为空;或将Aj并入Ai,并置Aj为空。
一般将元素少的集合合并到元素多的集合。
(3)A1,A2,…,An中所有非空子集构成的集合即为所求商集。
要实现集合的并运算,采用并查集(union-findsets)是一种不错的方法。
并查集是一种树型的数据结构,多棵树构成一个森林,每棵树构成一个集合,树中的每个节点就是该集合的元素,找一个代表元素作为该树(集合)的祖先。
并查集可用于快速实现处理一些不相交集合(DisjointSets)的并。
一般用途就是用来维护某种等价类。
并查集支持以下三种操作:
(1)Make_Set(x)把每一个元素初始化为一个集合
初始化后每一个元素的父亲节点是它本身,每一个元素的祖先节点也是它本身。
(2)Find_Set(x)查找一个元素所在的集合
查找一个元素所在的集合,只要找到这个元素所在集合的祖先即可。
判断两个元素是否属于同一集合,只要看他们所在集合的祖先是否相同即可。
(3)Union(x,y)合并x,y所在的两个集合
合并两个不相交集合操作很简单:
首先设置一个数组Father[x],表示x的"父亲"的编号。
那么,合并两个不相交集合的方法就是,找到其中一个集合的祖先,将另外一个集合的祖先指向它。
五 实验数据及结果分析
当输入的关系R不是等价关系是的提示结果
当输入集合A,同时输入一个正确的等价关系的结果
六 源程序清单
3(C类)
#include"stdio.h"
#include"ctype.h"
#include"string.h"
#include"stdlib.h"
#include"math.h"
#defineMAX20
#defineSTUstructstu
intM[MAX][MAX];/*存放关系矩阵*/
charA[MAX];/*存放有限集合*/
charB[MAX];/*存放等价关系*/
inti,j,p,q,n,l,k,t,y;
STU
{
intm;
chartree[20];
};
STUequ[20];
voidmake_set(STUequ[],charA[],intn)/*使集合A中的元素自成一个子集*/
{
inti;
for(i=0;i{
equ[i].m=1;
equ[i].tree[0]=A[i];
equ[i].tree[1]='\0';
}
}
find_set(intj)/*查找二元组中元素所属集合*/
{
inti;
for(i=0;i{
if(M[j][i])
{
break;
}
}
if(i==j)
{
return-1;
}
else
returni;
}
voidunionit(STUequ[],intj,inti)/*合并二元组中元素所属集合*/
{
equ[j].tree[equ[j].m]=equ[i].tree[0];
equ[i].tree[0]='\0';
equ[i].m=0;
equ[j].m=equ[j].m+1;
equ[j].tree[equ[j].m]='\0';
}
voiddisp(STUequ[],intn)/*输出商集*/
{
inti;
printf("A/R={");
for(i=0;i{
if(equ[i].m!
=0)
{
printf("{%s}",equ[i].tree);
}
}
printf("}");
}
voidcaculate(STUequ[],charA[],intn)/*计算商集*/
{
intp;
make_set(equ,A,n);
for(i=0;i{
p=find_set(i);
if(p!
=-1){
unionit(equ,p,i);
}
}
disp(equ,n);/*调用输出商集函数*/
}
voidgetguanxi()/*获得关系R并输出显示*/
{
gets(B);
l=strlen(B);
printf("您输入的关系为:
\n");
printf("R={");
for(j=0;j{
printf("<");
printf("%c,",B[j]);
printf("%c",B[j+1]);
printf(">");
}
printf("}\n");
}
voidtranslate()/*转换为关系矩阵的函数*/
{
intp,q,i=0,j;
while(B[i]!
='\0')
{
if((B[i]>='A')&&(B[i]<='Z'||B[i]>='a')&&
|
|