一问题描述.docx
- 文档编号:7971971
- 上传时间:2023-01-27
- 格式:DOCX
- 页数:14
- 大小:135.51KB
一问题描述.docx
《一问题描述.docx》由会员分享,可在线阅读,更多相关《一问题描述.docx(14页珍藏版)》请在冰豆网上搜索。
一问题描述
一、问题描述
大学每个专业都要制定教学计划。
假设任何专业都有固定的学习年限,每学年含两个学期的时间长短和学分上限值均相等。
每个专业开设的课程都是确定的,而且课程在开设时间的安排上必须满足先修关系。
每门课有哪些先修课程也是确定的(但可以有多门先修课程,也可以没有先修课程)。
每门课恰好占一学期。
试在这些前提下设计一个教学计划编制程序。
二、基本要求
(1):
输入参数:
学期总数,一学期的学分上限,每门课的课程号,学分,直接先修关系的课程号。
(2):
课程号尽可能的集中在前几个学期中。
(3):
若无解,则报告错误信息
三、数据结构的设计
采用邻接表存储结构,构造没有相关信息的图G,图中每个结点采用结构体数据类型,其中数据域存储先修课程的课程号和学分等相关数据,根据先修关系确定图中结点之间的关系。
例如下面语句是对表结点,头结点和图的定义:
typedefstructArcNode
{
intadjvex;/*该弧所指向的顶点的位置*/
structArcNode*nextarc;/*指向下一条弧的指针*/
InfoType*info;/*网的权值指针)*/
}ArcNode;/*表结点*/
typedefstruct
{
VertexTypedata;/*顶点信息*/
ArcNode*firstarc;/*第一个表结点的地址,指向第一条依附该顶点的弧的指针*/
}VNode,AdjList[MAX_VERTEX_NUM];/*头结点*/
typedefstruct
{
AdjListvertices,verticestwo;
intvexnum,arcnum;/*图的当前顶点数和弧数*/
intkind;/*图的种类标志*/
}ALGraph;
其中(*G).vexnum纪录教学计划的课程数,(*G).arcnum纪录拓扑排序所形成的课程先修关系的边数,(*G).vertices[i].data纪录课程的代表值,(*G).verticestwo[i].data纪录课程的学分值,va和vb为顺序输入每条弧(边)的弧尾和弧头。
并通过相关算法定义了相应的存储结构。
另外直接用INT数据类型xqzs,xfsx分别纪录学期总数和学期的学分上限。
四、软件模块结构图
五、程序设计思想
我们经常用有向图来描述一个工程或系统的进行过程。
一般来说,一个工程可以分为若干个工程,只要完成了这些子工程,就可以导致整个工程的完成。
每个子工程称为活动,在图中用顶点表示,两点之间的弧表示活动间的有限关系,这种有向图称为作业活动网或AOV网。
所以教学计划编制问题的数据模型就用拓扑排序AOV网结构。
如果我们要为AOV网中每项活动的进行安排一个线性序列关系,则必须以有向图的次序关系为前提。
另外在作业活动网中时不允许存在有向回路的,因为回路的出现意味着某项活动的开工将以自己工作的完成作为先决条件,这种现象称为死锁。
根据有向图构造一个线性序列,在这个序列中包含有向图的全部顶点,并且使得此序列中的顶点之间不仅保持有向图中原有的次序关系,而且在有向图中没有关系的顶点之间人为建立一个次序关系,这线性序列为拓扑有向序列,对AOV网构造拓扑有向序列的操作称为拓扑排序。
在计算机中实现拓扑序列的算法,首先要选定存储结构,在这采用邻接表存储结构,邻接表是图的一种链式存储结构,在邻接表中,对图中每个顶点建立一个单链表,每个链接点有三个域组成:
邻接域指示与顶点邻接的序号;链域指示下一条边或弧的结点;数据域存储和边或弧相关的信息,如权指等。
每个链表上附设一个表头结点,在表头结点中设有脸域指向链表中第一个结点,根据需要可设数据域存储顶点的有关信息,表头结点通常以顺序存储,称为邻接向量。
为便于考察每个顶点的入度,在每个邻接链表的头接点中增加一个存放顶点入度的数据域,以指示各顶点当前的入度数值。
为便于寻找邻接表中入度为零的顶点,设置一个头指针,将所有入度为零的顶点构成一个链栈,这样可以进行入度为零的顶点删除,又可以将新出现的入度为零的顶点随时入栈。
六、程序流程图
七、源程序
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/*函数结果状态代码*/
#defineTRUE1
#defineFALSE0
#defineOK1
#defineERROR0
#defineINFEASIBLE-1
typedefintStatus;/*Status是函数的类型,其值是函数结果状态代码,如OK等*/
typedefintBoolean;/*Boolean是布尔类型,其值是TRUE或FALSE*/
#defineMAX_NAME10
/*顶点字符串的最大长度*/
#defineMAXCLASS100
intZ=0;
intX=0;
intxqzs,q=1,xfsx;
typedefintInfoType;
typedefcharVertexType[MAX_NAME];/*字符串类型*/
/*图的邻接表存储表示*/
#defineMAX_VERTEX_NUM100
typedefenum{DG}GraphKind;/*{有向图,有向网,无向图,无向网}*/
typedefstructArcNode
{
intadjvex;/*该弧所指向的顶点的位置*/
structArcNode*nextarc;/*指向下一条弧的指针*/
InfoType*info;/*网的权值指针)*/
}ArcNode;/*表结点*/
typedefstruct
{
VertexTypedata;/*顶点信息*/
ArcNode*firstarc;/*第一个表结点的地址,指向第一条依附该顶点的弧的指针*/
}VNode,AdjList[MAX_VERTEX_NUM];/*头结点*/
typedefstruct
{
AdjListvertices,verticestwo;
intvexnum,arcnum;/*图的当前顶点数和弧数*/
intkind;/*图的种类标志*/
}ALGraph;
/*图的邻接表存储的基本操作*/
intLocateVex(ALGraphG,VertexTypeu)
{/*初始条件:
图G存在,u和G中顶点有相同特征*/
/*操作结果:
若G中存在顶点u,则返回该顶点在图中位置;否则返回-1*/
inti;
for(i=0;i if(strcmp(u,G.vertices[i].data)==0) returni; return-1; } StatusCreateGraph(ALGraph*G) {/*采用邻接表存储结构,构造没有相关信息的图G(用一个函数构造4种图)*/ inti,j,k; VertexTypeva,vb; ArcNode*p; printf("请输入教学计划的课程数: "); scanf("%d",&(*G).vexnum); printf("请输入拓扑排序所形成的课程先修关系的边数: "); scanf("%d",&(*G).arcnum); printf("请输入%d个课程的代表值(<%d个字符): \n",(*G).vexnum,MAX_NAME); for(i=0;i<(*G).vexnum;++i)/*构造顶点向量*/ {scanf("%s",(*G).vertices[i].data); (*G).vertices[i].firstarc=NULL; } printf("请输入%d个课程的学分值(<%d个字符): \n",(*G).vexnum,MAX_NAME); for(i=0;i<(*G).vexnum;++i)/*构造顶点向量*/ {scanf("%s",(*G).verticestwo[i].data); } printf("请顺序输入每条弧(边)的弧尾和弧头(以空格作为间隔): \n"); for(k=0;k<(*G).arcnum;++k)/*构造表结点链表*/ {scanf("%s%s",va,vb); i=LocateVex(*G,va);/*弧尾*/ j=LocateVex(*G,vb);/*弧头*/ p=(ArcNode*)malloc(sizeof(ArcNode));/*为指针分配空间*/ p->adjvex=j; p->info=NULL;/*图*/ p->nextarc=(*G).vertices[i].firstarc;/*插在表头*/ (*G).vertices[i].firstarc=p; } returnOK; } voidDisplay(ALGraphG) {/*输出图的邻接矩阵G*/ inti; ArcNode*p; switch(G.kind) {caseDG: printf("有向图\n"); } printf("%d个顶点: \n",G.vexnum); for(i=0;i printf("%s",G.vertices[i].data); printf("\n%d条弧(边): \n",G.arcnum); for(i=0;i { p=G.vertices[i].firstarc; while(p) {printf("%s: %s",G.vertices[i].data,G.vertices[p->adjvex].data); p=p->nextarc; } printf("\n"); } } voidFindInDegree(ALGraphG,intindegree[]) {/*求顶点的入度,算法调用*/ inti; ArcNode*p; for(i=0;i indegree[i]=0;/*赋初值*/ for(i=0;i { p=G.vertices[i].firstarc; while(p) {indegree[p->adjvex]++; p=p->nextarc; } } } typedefintSElemType;/*栈类型*/ /*栈的顺序存储表示*/ #defineSTACK_INIT_SIZE10/*存储空间初始分配量*/ #defineSTACKINCREMENT2/*存储空间分配增量*/ typedefstructSqStack { SElemType*base;/*在栈构造之前和销毁之后,base的值为NULL*/ SElemType*top;/*栈顶指针*/ intstacksize;/*当前已分配的存储空间,以元素为单位*/ }SqStack;/*顺序栈*/ /*顺序栈的基本操作*/ StatusInitStack(SqStack*S) {/*构造一个空栈S*/ (*S).base=(SElemType*)malloc(sizeof(SElemType)*STACK_INIT_SIZE);/*分配空间*/ if(! (*S).base) exit(OVERFLOW);/*存储分配失败,终结程序*/ (*S).top=(*S).base; (*S).stacksize=STACK_INIT_SIZE; returnOK; } StatusStackEmpty(SqStackS) {/*若栈S为空栈,则返回TRUE,否则返回FALSE*/ if(S.top==S.base) returnTRUE; else returnFALSE; } StatusPop(SqStack*S,SElemType*e) {/*若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR*/ if((*S).top==(*S).base) returnERROR; *e=*--(*S).top; returnOK; } StatusPush(SqStack*S,SElemTypee) {/*插入元素e为新的栈顶元素*/ if((*S).top-(*S).base>=(*S).stacksize)/*栈满,追加存储空间*/ { (*S).base=(SElemType*)realloc((*S).base,((*S).stacksize+STACKINCREMENT)*sizeof(SElemType)); if(! (*S).base) exit(OVERFLOW);/*存储分配失败*/ (*S).top=(*S).base+(*S).stacksize; (*S).stacksize+=STACKINCREMENT; } *((*S).top)++=e; returnOK; } typedefintpathone[MAXCLASS]; typedefintpathtwo[MAXCLASS]; StatusTopologicalSort(ALGraphG) {/*有向图G采用邻接表存储结构。 若G无回路,则输出G的顶点的一个拓扑序列并返回OK,*/ /*否则返回ERROR。 */ inti,k,count,indegree[MAX_VERTEX_NUM]; SqStackS; pathonea; pathtwob; ArcNode*p; FindInDegree(G,indegree);/*对各顶点求入度indegree[0..vernum-1]*/ InitStack(&S);/*初始化栈*/ for(i=0;i if(! indegree[i]) Push(&S,i);/*入度为0者进栈*/ count=0;/*对输出顶点计数*/ while(! StackEmpty(S)) {/*栈不空*/ Pop(&S,&i); a[i]=*G.vertices[i].data; b[i]=*G.verticestwo[i].data; printf("课程%s: 学分%s",G.vertices[i].data,G.verticestwo[i].data); /*输出i号顶点并计数*/ ++count; for(p=G.vertices[i].firstarc;p;p=p->nextarc) {/*对i号顶点的每个邻接点的入度减1*/ k=p->adjvex; if(! (--indegree[k]))/*若入度减为0,则入栈*/ Push(&S,k); } } if(count {printf("此有向图有回路\n"); returnERROR; } else {printf("\n为一个拓扑序列。 \n"); } while(q<=xqzs) {intC=0; if(X<=G.arcnum) {while(C<=xfsx) {C+=*G.verticestwo[Z].data; ++Z; } printf("\n第%d个学期应学课程: ",q); while(X<=Z) {printf("%s",G.vertices[X].data); ++X; } printf("\n"); q++; } else {printf("\n"); returnOK; } } returnOK; } voidmain() {ALGraphf; printf("教学计划编制问题的数据模型为拓扑排序AOV-网结构。 \n"); printf("以下为教学计划编制问题的求解过程: \n"); printf("\n请输入学期总数: "); scanf("%d",&xqzs); printf("请输入学期的学分上限: "); scanf("%d",&xfsx); CreateGraph(&f); Display(f); TopologicalSort(f); getch(); } 八、调试分析 在刚开始编译程序的时候,出现的问题还是比较多的。 经常在函数调用的时候对变量定义有错或者忘记定义,对局部变量和全局变量经常混淆。 出现过没有返回值的情况,分析了一下,发现可能是在函数类型开始没有定义函数是有返回值的还是没有返回值,即VIOD类型的,如果不是VIOD类型的,要在结尾加上适当的return语句。 由于软件TC不支持中文,所以改用VC++6.0调试并运行,发现编译没错和警告,但是运行程序之后,屏幕一闪之后就消失。 反复看程序,知道在开始定义的时候加上#include 九、测试数据 用VC++6.0软件运行程序,按屏幕提示输入数据: 其中学期总数为7,学期的学分上限为12,教学计划的课程数为5,拓扑排序所形成的课程先修关系的边数为4,课程代表值为ABCDE,课程的学分值为42312,顺序输入每条弧(边)的弧尾和弧头为12233445,得出如下图中所示数据: 十、用户使用手册 由于程序中要显示中文字符,所以编程时用了VC++6.0。 用户运行程序之后,应该按照屏幕显示的输入相应的数据(注意数据的类型和字符串的长度),以回车键结束,当输入数据数量满足所定要求时,按回车键只会实现换行功能,当发现有这种情况出现时,可以继续输入数据,直到满足要求的数据的数量为止,此时按回车可以进行下一步操作。 而且用户所输入的课程数的数量必须小于先修关系的边数,否则会出现错误。 在输入数据的时候不能输入与要求不一致的数据,如程序要求输入数字,用户如果输入字符,则会出现乱码。 十一、心得体会 在程序设计过程中,由于多次用到了结构体数据类型和指针数据类型,所以在定义这些数据类型的时候应该要比较清楚所定义变量的含义和功能,在定义结构体数据类型时,用到typedef这一关键字,用typedef定义新的类型名后,对于结构体和枚举类型,使用它们定义或说明变量时不必再冠以类型类别关键字,作为类型定义,它只定义数据结构,并不要求分配存储单元。 在运用指针数据类型时应熟悉指针变量的使用格式,注意指针类型变量的使用。 在栈和邻接表的 使用过程中,出现了比较大的难度,在参考了课本《计算机软件技术基础》和《C语言程序设计教程》以及《数据结构》之后,对那两部分内容有了一定的了解,在指导老师的帮助下,出现的问题基本上都得到解决了。 通过这次课程设计,对数据结构的内容和运用有了一定的了解,通过参考书籍和请教老师,对C语言编程有了进一步的认识和熟悉,也学到了许多课外知识。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 问题 描述