中南大学离散数学实验报告实验ABC.docx
- 文档编号:27281129
- 上传时间:2023-06-28
- 格式:DOCX
- 页数:18
- 大小:130.94KB
中南大学离散数学实验报告实验ABC.docx
《中南大学离散数学实验报告实验ABC.docx》由会员分享,可在线阅读,更多相关《中南大学离散数学实验报告实验ABC.docx(18页珍藏版)》请在冰豆网上搜索。
中南大学离散数学实验报告实验ABC
“离散数学”实验报告
(实验3ABC)
专业
班级
学号
姓名
日期:
2011.12.19
目录
一、实验目的3
二、实验内容3
三、实验环境3
四、实验原理和实现过程(算法描述)3
1实验原理3
2实验过程5
五、实验数据及结果分析6
六、源程序清单10
七、其他收获及体会16
一、实验目的
理解图论的基本概念,图的矩阵表示,图的连通性,图的遍历,以及求图的连通支方法。
二、实验内容
以偶对的形式输入一个无向简单图的边,建立该图的邻接矩阵,判断图是否连通(A)。
并计算任意两个结点间的距离(B)。
对不连通的图输出其各个连通支(C)。
三、实验环境
C或C++语言编程环境实现。
四、实验原理和实现过程(算法描述)
1、实验原理
(1)建立图的邻接矩阵,判断图是否连通
根据图的矩阵表示法建立邻接矩阵A,并利用矩阵的乘法和加法求出可达矩阵,从而判断图的连通性。
连通图的定义:
在一个无向图G中,若从顶点vi到顶点vj有路径相连(当然从vj到vi也一定有路径),则称vi和vj是连通的。
如果G是有向图,那么连接vi和vj的路径中所有的边都必须同向。
如果图中任意两点都是连通的,那么图被称作连通图。
判断连通图的实现:
在图中,从任意点出发在剩余的点中,找到所有相邻点循环,直到没有点可以加入为止,如果有剩余的点就是不连通的,否则就是连通的。
或者也可用WallShell算法,由图的邻接矩阵判断图是否连通。
(2)计算任意两个结点间的距离
图中两点i,j间的距离通过检验Al中使得aij为1的最小的l值求出。
路径P中所含边的条数称为路径P的长度。
在图G
设图的邻接矩阵是A,则所对应的aij的值表示,点Vi到点Vj距离为n的路径有aij条。
若aij
(1),aij
(2),…,aij(n-1),中至少有一个不为0,则可断定Vi与Vj可达,使aij(l)≠0的最小的l即为d(Vi,Vj)。
问题求解原理为:
(1)先构造初始邻接矩阵A=Vij,Vij为顶点Vi到顶点Vj的权。
如果Vi和Vj之间不存在弧段或者是负向回路或者是i=j,则令Vij其值为∞。
(2)再构造初始中间顶点矩阵。
(3)然后开始迭代计算(迭代的次数等于顶点的个数1)
(4)最后查找Vi到Vj的最短路径。
计算节点Vi与Vj之间的距离的方法为:
利用邻接矩阵相互间相乘后得到的矩阵来判断节点间的距离。
如果c2[s][i][j]==0,则这两个节点的距离为无穷大。
如果c2[s-2][i][j]==0,c2[s-1][i][j]==1时,则这两点间的距离为s。
(3)对不连通的图输出其各个连通支
图的连通支的求法则可采用图的遍历算法,图的遍历有深度优先和广度优先两种方法,其中深度优先算法又分为递归和非递归两种。
在无向图中,如果任何两点可达,则称图G是连通的,如果G的子图G’是连通的,没有包含G’的更大的子图G’’是连通的,则称G’是G的连通支。
当有判断出关系不是连通的之后,将需要求出分支模块
实现方法如下:
先定义一个二维数组用来存放相应的分块,先选定一个点,并将它放在数组中,然后判断,如果后面的和他是联通的便将它也放在同一个数组中,否则将其存入其他的数组中,后面以此类推,在输出相应的数组,便可判断出连通分支。
2、实验过程
(1)程序整体思路
本程序完成了实验所要求的全部功能,其基本思路是——“运用模块化的思想,将实现“求连通支”、“输入结点关系”、“输出邻接矩阵”、“显示两结点间的距离”、“求可达矩阵”和“图的遍历”的子函数分开编写,然后将它们以子函数的形式添加到主函数main的代码后面,在要使用相应的子函数时,进行子函数调用就可以实现相应的功能了。
”
本程序的一大特色就是开发者灵活使用了C语言中的数组概念来进行开发,用数组来模拟矩阵的运算,通过相应的算法实现了全部的功能。
(2)具体算法流程
在main(){系统界面显示;用do…while循环语句和switch语句实现功能1,2,3……的选择,并调用相关的子程序;用start、gotostart实现控制流的转移;}
liantongzhi(){求连通支,此子函数通过一个for循环控制遍历每个结点,并调用函数DFS()求每个结点的连通支;}
DFS(inta){通过实参与形参,将结点数据代入函数;定义顺序栈变量;通过for循环初始化;为a置已访问标志,已经访问了的元素为1;定义顺序栈的第一个元素;通过while循环实现结点遍历,栈不为空时执行循环;栈顶元素赋值;通过for循环寻找v的下个未访问的邻接点;通过if条件句,若x,i是边和节点i未被访问过,处理结点的访问,并进行访问标志,进栈等操作;通过if条件句,若v已访问到的出点,则将其退栈;}
shuru(){输入结点关系;通过for循环先将矩阵所有元素赋值0;再通过另一for循环,根据输入结点的关系,将矩阵中相应的元素赋值,有关系则为1;}
linjiejuzhen(){输出邻接矩阵;通过for循环,依次按格式输出邻接矩阵的元素;}
julijuzhen(){根据A的n次方矩阵及其中元素,判断并显示两结点间的距离;调用子函数linjiejuzhen(),以确定并显示距离为1的两结点;通过for循环显示距离为1的结点对;再通过一系列的for循环,计算A的n次方矩阵并显示结果,根据其中的元素,判断并显示结点间的距离;详细算法请见附录相关部分的注释;}
kedajuzhen(){求可达矩阵;通过一系列for循环,根据公式,计算可达矩阵;通过for循环,将矩阵中不为0的一切值赋为1以生成可达矩阵并显示;通过for循环和if条件句的组合,根据可达矩阵的元素特点,判断图的连通性,若可达矩阵矩阵中有0,则跳出循环,显示不可连接;根据判断结果显示内容,不可连通或可连通;}
五、实验数据及结果分析
1输入界面
简单无向图的输入界面友好,有清楚的操作说明,方便用户进行使用。
这就是集合的输入界面。
2输入无向图的边
当“6,5”时,表示输入的是六个节点五条边的树。
3建立图的连接矩阵
程序返回主界面后,选择“2”,程序会显示建立的连接矩阵
4计算节点间的距离
当选择“3”时,程序便会输出各节点间的距离。
5判断图的连通性
当选择“4”时,程序会根据可达矩阵判断图的连通性。
6输出图的连通支
当选择“5”时,程序会输出个连通支。
7退出系统
当选择“6”时,程序会退出系统。
六、源程序清单
#include
#include
#include
#defineMAX100/*宏定义*/
typedefstruct{intelem[MAX];
inttop;
}SqStack;/*定义栈的结构体,顺序栈的类型标识符*/
voidshuru();/*各子函数声明*/
voidlinjiejuzhen();
voidjulijuzhen();
voidkedajuzhen();
voidliantongzhi();
voidDFS(inta);
intA[9][9],B[9][9],C[9][9],D[9][9];
inti,j,k,t,v,e;
intmain()
{
inta1;
start:
do
{
printf("\n");
printf("*******************************************************************************\n");
printf("\n");
printf("\t\t\t\t系统主菜单\n");
printf("\n\t\t1.输入无向图的边\n\t\t2.建立图的邻接矩阵\n\t\t3.计算节点间的距离\n");
printf("\t\t4.由可达矩阵判断图的连通性\n\t\t5.输出各个连通支(深度优先DFS法)\n\t\t6.退出系统\n");
printf("\n");
printf("********************************************************************************\n");
printf("\n");
printf("\n\t\t\t\t请输入功能选项:
");
fflush(stdin);/*清空输入缓冲区,通常是为了确保不影响后面的数据读取*/
scanf("%d",&a1);
switch(a1)/*switch语句实现选择功能*/
{
case1:
system("cls");shuru();break;/*输入节点关系,计算邻接矩阵*/
case2:
system("cls");fflush(stdin);linjiejuzhen();break;/*输出邻接矩阵*/
case3:
system("cls");fflush(stdin);julijuzhen();break;/*求距离矩阵*/
case4:
system("cls");fflush(stdin);kedajuzhen();break;/*求可达矩阵*/
case5:
system("cls");fflush(stdin);liantongzhi();break;/*求连通支*/
case6:
system("exit");exit(0);/*结束整个程序的运行*/
default:
system("cls");
gotostart;/*控制流转移到start处*/
}
}while
(1);
}
voidliantongzhi()/*求连通支,此子函数控制遍历每个结点*/
{
for(i=1;i<=v;i++)
{
printf("%d",i);
DFS(i);/*调用子函数求连通支*/
printf("\n");
}
}
voidDFS(inta)/*由深度优先DFS法求出并显示各个连通支*/
{
inti,x;
inttop=0;
intvisited[MAX];
SqStacks;/*定义s为顺序栈变量*/
for(i=0;i<100;i++)
visited[i]=0;/*初始化为0*/
visited[a-1]=1;/*为a置已访问标志,已经访问了的元素为1*/
top=top+1;
s.elem[top]=a-1;/*顺序栈的第一个元素*/
while(top!
=0)/*栈不为空时执行循环*/
{
x=s.elem[top];/*将栈顶元素付给x*/
for(i=0;i if(D[x][i]! =0&&(! visited[i]))/*若x,i是边和节点i未被访问过*/ { printf("->%d",i+1); visited[i]=1;/*为i置已访问标准*/ top=top+1; s.elem[top]=i;/*i进栈*/ break; } if(i==v)/*若v已访问到的出点,则将其退栈*/ top--; } } voidshuru()/*输入结点关系*/ { printf("*******************************************************************************\n"); printf("\n"); printf("\t\t请输入结点数和边数(形式如6,5): \n"); scanf("%d,%d",&v,&e);/*输入结点和边数*/ for(i=0;i { for(j=0;j { A[i][j]=0; C[i][j]=0; B[i][j]=0; D[i][j]=0; } } printf("\n"); printf("*******************************************************************************\n"); printf("\t\t请输入结点间的关系(形式如: 1,2): \n"); printf("\n"); for(k=0;k { scanf("%d,%d",&i,&j); A[i-1][j-1]=1;/*根据输入结点的关系,将矩阵中相应的元素赋值*/ A[j-1][i-1]=1; B[i-1][j-1]=1; B[j-1][i-1]=1; D[i-1][j-1]=1; D[j-1][i-1]=1; } system("cls"); } voidlinjiejuzhen()/*输出邻接矩阵*/ { printf("邻接矩阵A为: \n"); for(i=0;i { for(j=0;j { printf("\t%5d",A[i][j]);/*显示邻接矩阵*/ } printf("\n"); } printf("\n"); } voidjulijuzhen()/*根据A的n次方矩阵及其中元素,判断并显示两结点间的距离*/ { linjiejuzhen();/*调用子函数,以确定并显示距离为1的两结点*/ for(i=1;i<=v;i++) { for(j=1;j<=v;j++) { if(A[i-1][j-1]==1) printf("结点%d与结点%d的距离为: %d\n",i,j,1); } } for(k=2;k<=v-1;k++)/*计算并显示距离大于1的两节点*/ { printf("\n\n"); printf("距离为%d的矩阵(即A%d)为: \n",k,k); { for(i=0;i for(j=0;j { for(t=0;t C[i][j]=C[i][j]+B[i][t]*A[t][j];/*计算矩阵中的元素*/ } for(i=0;i for(j=0;j { B[i][j]=C[i][j];/*将计算出的结果赋予B矩阵*/ C[i][j]=0; } } for(i=0;i { for(j=0;j printf("\t%5d",B[i][j]);/*显示距离矩阵*/ printf("\n"); } printf("\n"); for(i=1;i<=v;i++) for(j=1;j<=v;j++) { if(A[i-1][j-1]==0&&B[i-1][j-1]! =0&&i! =j)/*判断条件,以确定输出对象(相关的点)*/ printf("结点%d与结点%d的距离为: %d\n",i,j,k); } } printf("\n"); } voidkedajuzhen()/*求可达矩阵*/ { intl=1; printf("可达矩阵为: \n"); for(i=0;i for(j=0;j { B[i][j]=A[i][j]; C[i][j]=0; } for(k=0;k { for(i=0;i for(j=0;j { for(t=0;t C[i][j]=C[i][j]+B[i][t]*A[t][j];/*根据公式计算可达矩阵*/ } for(i=0;i for(j=0;j { D[i][j]=C[i][j]+D[i][j];/*根据公式计算可达矩阵*/ } for(i=0;i for(j=0;j { B[i][j]=C[i][j];/*根据公式计算可达矩阵*/ C[i][j]=0; } } for(i=0;i { for(j=0;j if(D[i][j]>=1)/*将矩阵中不为0的一切值赋为1以生成可达矩阵*/ D[i][j]=1; } for(i=0;i { for(j=0;j printf("\t%5d",D[i][j]);/*显示可达矩阵*/ printf("\n"); } for(i=0;i { for(j=0;j if(D[i][j]==0)/*若可达矩阵矩阵中有0,则跳出循环,显示不可连接*/ l=0; break; } if(l==0)/*根据上一步判断结果显示内容*/ printf("\n\t\t\t\t该图不连通! "); else printf("\n\t\t\t\t该图可连通! "); } 七、其他收获及体会 这次是最后一次实验,不过这次跟前两次有点不同,这次实验内容是关于图论的,理解图论的基本概念,图的矩阵表示,图的连通性,图的遍历,以及求图的连通支方法。 和前两次的实验一样,我做了相同的准备,先复习巩固了图论的相关知识,学习程序所要用到的C语言知识,同时上网查找相关的知识。 通过本次离散数学实验,我学到很多东西,不仅可以巩固了以前所学过的知识,而且通过查阅相关资料,学到了很多在书本上所没有学到过的知识。 同时我对于离散数学中的“逻辑”有了进一步的理解,对C语言的理解也更进了一步,并提高了编写实验报告、总结实验结果的能力,提高了理论联系实际的能力,初步具备程序设计的思想,能够独立完成简单的算法设计和分析。 通过这三次的离散数学实验,我不仅学到了各种有用的知识,最重要的是锻炼了自己的能力,加强了自己的毅力,使自己能够沉着冷静地应对各种问题,培养耐心,努力找出问题的关键,从而采取最有效的方案进行问题解决。 做实验中,我也明白了,我们无论做什么事,都要多想,多问,多做,这样才能把事情做好,从而真正地学到知识,提升自我。 我现在已经信心十足,准备迎接下一个挑战。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 中南 大学 离散数学 实验 报告 ABC