文章目录
前言
学校的课程作业,存在一点小问题(课程均匀分布 Order_slow()部分 ),但也通过了。
最近有点忙,实在改不了,要是有大佬能指教一番,感激不尽。
实验要求
项目名称:教学计划编制系统
项目内容:
1.大学的每个专业都要制定教学计划。假设任何专业都有固定的学习年限,每学年包含两个学期,每个学期的时间长度和学分上限均相等。每个专业开设的课程都是确定的
2.课程在开设时间的安排上必须满足先修关系。每门课程有哪些先修课程是确定的,可以有任意多门,也可以没有。每门课恰好占一个学期。试在这样的前提下设计一个教学计划编制系统,该系统需要满足以下功能。
(1) 完成课程进修目录信息的读取。
(2) 完成课程进修目录信息的编辑,包括课程的增加,删除,信息修改等。
(3) 学生的教学计划学期为 6,每个学期的学分上限为 10 分,允许用户指定下列编排策略进行教
学计划的输出
1)使学生在各个学期中的负担尽量均匀;
2)使课程尽可能地集中在前几个学期中 若根据给定的条件问题无解,则报告适当信息;否则将教
学计划输出到用户指定的文件中
流程
课程数据预设 课程信息修改 拓扑排序 选择方案
成果(course.txt)
Courses for year 2023 semester 1:
1 程序设计基础 2
9 高等数学 7
Courses for year 2023 semester 2:
2 离散数学 3
4 汇编语言 3
10 线性代数 5
Courses for year 2023 semester 3:
11 普通物理 2
3 数据结构 4
Courses for year 2023 semester 4:
6 计算机原理 3
12 数值分析 3
5 程序设计与分析 2
Courses for year 2023 semester 5:
8 操作系统 4
7 编译原理 4
Courses for year 2023 semester 6:
13 软件工程 3
14 数据库原理 3
菜单
void showMenu()
{
cout << "1.预定课程导入" << endl;
cout << "2.添加课程" << endl;
cout << "3.删除课程" << endl;
cout << "4.更新课程" << endl;
cout << "5.拓扑排序" << endl;
cout << "6.排序结果" << endl;
cout << "7.方案选择" << endl;
cout << "8.修改限制" << endl;
cout << "9.展示图" << endl;
cout << "10.退出" << endl;
cout << "请选择你的英雄:";
}
int main(void)
{
// 创建一个ALGraph类型的指针变量graph
ALGraph *graph = new ALGraph();
// 创建一个VNode类型的指针变量slow,初始值为NULL
VNode *slow = NULL;
// 创建一个VNode类型的指针变量fast,初始值为NULL
VNode *fast = NULL;
// 创建一个VNode类型的指针变量p,初始值为NULL
VNode *p = NULL;
// 创建一个int类型的变量choose,初始值为0
int choose = 0;
// 打印出欢迎信息
cout << sp << "欢迎来到课程管理系统" << sp << endl;
// 创建一个无限循环
while (true)
{
// 调用showMenu函数,显示菜单
showMenu();
// 创建一个int类型的变量choose,初始值为0
int choose;
// 调用cin函数,输入choose的值
cin >> choose;
// 根据choose的值,进行不同的操作
switch (choose)
{
// 如果choose的值为1,调用setClass函数,设置课程
case 1:
setClass(graph);
cout << endl;
break;
// 如果choose的值为2,调用addVex函数,添加顶点
case 2:
addVex(graph);
cout << endl;
break;
// 如果choose的值为3,调用deleteVex函数,删除顶点
case 3:
deleteVex(graph);
cout << endl;
break;
// 如果choose的值为4,调用renewVex函数,更新顶点
case 4:
renewVex(graph);
cout << endl;
break;
// 如果choose的值为5,调用graph的Order_slow函数,获取slow
case 5:
slow = graph->Order_slow();
cout << endl;
// 调用graph的Order_fast函数,获取fast
fast = graph->Order_fast();
cout << endl;
break;
// 如果choose的值为6,判断fast和slow是否为空,不为空则调用graph的Arrange函数,进行拓扑排序
case 6:
if (fast != NULL || slow != NULL)
{
p = fast;
cout << "拓扑排序结果为:" << endl;
cout << "fast:" << endl;
if (p != NULL)
{
for (int i = 0; i < graph->vexnum; i++)
{
cout << p->data.index << " ";
p++;
}
}
else
{
cout << "none" << endl;
}
cout << endl
<< "slow:" << endl;
p = slow;
if (p != NULL)
{
for (int i = 0; i < graph->vexnum; i++)
{
cout << p->data.index << " ";
p++;
}
}
else
{
cout << "none" << endl;
}
}
else
{
cout << "没有拓扑排序结果" << endl;
}
cout << endl;
break;
// 如果choose的值为7,调用graph的Arrange函数,进行拓扑排序
case 7:
cout << "请输入你的选择(slow:1 fast:2):";
cin >> choose;
if (choose == 1 && slow != NULL)
{
graph->Arrange(slow, 1);
}
else if (choose == 2 && fast != NULL)
{
graph->Arrange(fast, 2);
}
break;
// 如果choose的值为8,调用graph的change_Limit函数,修改课程限制
case 8:
graph->change_Limit();
break;
// 如果choose的值为9,调用graph的DisGraph函数,显示课程图
case 9:
graph->DisGraph();
break;
// 如果choose的值为10,结束程序
case 10:
return 0;
}
}
return 0;
}
setClass(实验数据的预设)
void setClass(ALGraph *graph)
{
vector<VNode> data(14);
vector<ArcInfo> arcList(19);
data[0] = {1, "程序设计基础", 2};
data[1] = {2, "离散数学", 3};
data[2] = {3, "数据结构", 4};
data[3] = {4, "汇编语言", 3};
data[4] = {5, "程序设计与分析", 2};
data[5] = {6, "计算机原理", 3};
data[6] = {7, "编译原理", 4};
data[7] = {8, "操作系统", 4};
data[8] = {9, "高等数学", 7};
data[9] = {10, "线性代数", 5};
data[10] = {11, "普通物理", 2};
data[11] = {12, "数值分析", 3};
data[12] = {13, "软件工程", 3};
data[13] = {14, "数据库原理", 3};
arcList[0] = {data[0], data[1], 2};
arcList[1] = {data[0], data[3], 2};
arcList[2] = {data[0], data[2], 2};
arcList[3] = {data[0], data[11], 2};
arcList[4] = {data[1], data[2], 2};
arcList[5] = {data[3], data[4], 2};
arcList[6] = {data[4], data[12], 2};
arcList[7] = {data[2], data[4], 2};
arcList[8] = {data[2], data[6], 2};
arcList[9] = {data[6], data[13], 2};
arcList[10] = {data[4], data[6], 2};
arcList[11] = {data[8], data[11], 2};
arcList[12] = {data[8], data[9], 2};
arcList[13] = {data[8], data[10], 2};
arcList[14] = {data[9], data[11], 2};
arcList[15] = {data[10], data[5], 2};
arcList[16] = {data[5], data[7], 2};
arcList[17] = {data[7], data[13], 2};
arcList[18] = {data[2], data[7], 2};
graph->CreateGraph(data.size(), arcList.size(), data.data(), arcList.data());
}
CreateGraph(根据预设的数据创建图)
void ALGraph::CreateGraph(int vnum, int anum, VNode vexList[], ArcInfo arcList[])
{
arcnum = anum;
vexnum = vnum;
for (int i = 0; i < vnum; i++)
{
vertices[i] = vexList[i];
vertices[i].firstarc = NULL;
vertices[i].in = 0;
}
for (int i = 0; i < anum; i++)
{
ArcNode *a = new ArcNode();
a->adjvex = arcList[i].To.data.index - 1;
a->nextarc = NULL;
a->weight = arcList[i].weight;
if (!vertices[arcList[i].From.data.index - 1].firstarc)
{
vertices[arcList[i].From.data.index - 1].firstarc = a;
}
else
{
/*
ArcNode *p = vertices[arcList[i].From.data.index - 1].firstarc;
while (p->nextarc != NULL)
{
p = p->nextarc;
}
p->nextarc = a; // 尾插法 不行
vertices[arcList[i].From.data.index - 1].in++; // 入度+1
*/
a->nextarc = vertices[arcList[i].From.data.index - 1].firstarc; // 头插法
vertices[arcList[i].From.data.index - 1].firstarc = a;
}
vertices[arcList[i].To.data.index - 1].in++; // 入度+1
}
cout << "CreateGraph Successfully!" << endl;
}
getVertices(建副本,保护原始数据)
VNode *ALGraph::getVertices()
{
VNode *v = new VNode[vexnum];
for (int i = 0; i < vexnum; i++)
{
v[i] = vertices[i];
}
return &v[0];
}
addVex(添加课程信息)
void ALGraph::addVex(VNode vex[], int prenum, int pre[], int postnum, int post[])
{
int i;
bool flag = false;
for (i = 0; i < vexnum; i++)
{
if (vertices[i].data.classname == vex->data.classname || vertices[i].data.index == vex->data.index)
{
flag = true;
break;
}
}
if (flag)
{
if (vertices[i].data.classname == vex->data.classname)
{
cout << "you already get it " << endl;
if (vertices[i].data.index == -1)
{
cout << "but the index of the course is -1" << endl
<< "if you want to add it ,please renew the index of the course" << endl;
}
}
if (vertices[i].data.index == vex->data.index)
{
cout << "sorry,you already get it" << endl
<< "some course have the same index" << endl
<< "please change the index of the course" << endl;
}
return;
}
DisGraph(输出邻接表)
void ALGraph::DisGraph()
{
VNode *vertices = getVertices();
string sp = "->";
for (int i = 0; i < vexnum; i++)
{
ArcNode *p = vertices[i].firstarc;
if (vertices[i].data.index != -1)
{
cout << vertices[i].data.index << sp;
while (p != NULL)
{
cout << p->adjvex + 1 << sp;
p = p->nextarc;
}
cout << endl;
// 输出入度
// cout << endl
// << vertices[i].in << endl;
}
else
{
cout << "deleted: " << vertices[i].data.classname << " credit:" << vertices[i].data.credit << endl;
}
}
}
Order_fast(将课程尽量排在前几个学期)
思路
每个循环一个学期
每个循环将入度为零的结点和其链表的首结点入栈
全部结点入栈后 从栈中取出链表首结点
循环,依次将其邻接点入度减一通过以上操作,使得每学期能学的课程尽量多地被选上
VNode *ALGraph::Order_fast()
{
// 副本,便于课程信息更新后重新排序
VNode *vertices = getVertices();
// 初始化变量
int i = 0;
bool flag = true;
ArcNode *p;
stack<VNode> vs;
stack<ArcNode *> as;
// 初始化标志位
while (flag) // 一个循环一个学期,每次都取入度为零的
{
flag = false;
// 遍历所有顶点,入度为0者入栈
for (i = 0; i < vexnum; i++)
{
if (vertices[i].in == 0 && vertices[i].data.index != -1)
{
vs.push(vertices[i]);
// cout << vertices[i].data.index << " " << vertices[i].data.classname << endl;
vertices[i].in--;
flag = true;
p = vertices[i].firstarc;
as.push(p);
}
} // 先取完入度为零的结点,再把邻接点减一
while (!as.empty())
{
p = as.top();
as.pop();
while (p != NULL)
{
vertices[p->adjvex].in--;
p = p->nextarc;
}
}
}
// 判断是否成环
i = vs.size();
// cout << "vs.size() = " << i << endl;
// cout << "vexnum = " << vexnum << endl;
if (i < vexnum)
{
cout << "there is cycle!" << endl;
return NULL;
}
// 初始化结果数组
VNode *result = new VNode[vexnum];
// 弹栈,将结果存入数组
for (i = 0; i < vexnum; i++)
{
if (!vs.empty())
{
result[i] = vs.top();
vs.pop();
}
else
{
cout << "there is something wrong with the stack!" << endl;
}
}
cout << "slow:success!" << endl;
return result;
}
Order_slow(课程均匀分布)
感觉这部分思路有点问题,但说不出来
思路
遍历结点如果入度为零
入栈 邻接点入度减一 重新遍历
否则
下一个结点我的理解
取完就将邻接点入度减一,课程安排更紧凑
比如,要学物理就要先学高等数学 A->B
如果先将高等数学选了,入度就减一的话
就可以在同一学期内学物理了(这并不符合规定,在后面的选择方案中物理会被安排到下一学期去)
借鉴于教学计划编制问题(数据结构 有向图 拓扑排序)
VNode *ALGraph::Order_slow()
{
VNode *vertices = getVertices();
// 定义一个计数变量i
int i = 0;
// 定义一个指针p
ArcNode *p;
// 定义一个栈vs
stack<VNode> vs;
// 定义一个栈as
stack<ArcNode *> as;
// 遍历每一个顶点
for (i = 0; i < vexnum; i++)
{
// 如果该顶点的入度为0
if (vertices[i].in == 0)
{
// 将该顶点压入栈vs
vs.push(vertices[i]);
// 将该顶点的入度减1
vertices[i].in--; // in=-1
// 将该顶点的指针p赋值给p
p = vertices[i].firstarc;
// 遍历该顶点的指针p
// 取完就将邻接点入度减一,课程安排更紧凑
// 比如,要学物理就要先学高等数学 A->B
// 如果先将高等数学选了,就可以在同一学期内学物理了
while (p)
{
// 将该顶点的入度减1
vertices[p->adjvex].in--;
// 将p的指针赋值给p
p = p->nextarc;
}
// 将i赋值为-1
i = -1; // 假如有新的课选上了,就重新遍历
}
}
i = vs.size();
if (i < vexnum)
{
cout << "there is cycle!" << endl;
return NULL;
}
VNode *result = new VNode[vexnum];
for (i = 0; i < vexnum; i++)
{
if (!vs.empty())
{
result[i] = vs.top();
vs.pop();
}
else
{
cout << "there is something with the stack" << endl;
return NULL;
}
}
cout << "fast:success!" << endl;
return result;
}
Arrange(判断排序的结果是否符合要求,符合则写入文件)
void ALGraph::Arrange(VNode *vnode, int choose)
{
// 声明一个变量vex,指向vnode
VNode *vex = vnode;
// 声明一个变量course,用于记录当前课程
int course;
// 声明一个变量s,用于记录当前课程的编号
int s = 0;
// 声明一个vector,用于记录每个课程的编号
vector<int> course_list(vexnum, 0);
// 声明一个vector,用于记录每个学期的课程数
vector<int> semester_list(limit.term, 0);
// 遍历vex,打印每个课程的编号和课程信息
while (s < vexnum)
{
cout << s << " " << vex[s].data.classname << endl;
s++;
}
// 声明一个变量arranged_num,用于记录已排列的课程数
int arranged_num = 0;
// 声明一个变量credit_sum,用于记录已排列课程的总学分
int credit_sum = 0;
// 声明一个变量course_num,用于记录本学期课程数
int course_num = 0;
// 声明一个变量per_maxcourse,用于记录每个学期最多可以上多少门课程
// int per_maxcourse = 0;
// 声明一个布尔变量flag,用于记录是否找到可以上当前课程的邻接课程
bool flag = true;
// 声明一个指针变量q,用于遍历当前学期课程列表
ArcNode *q;
// 声明一个队列变量vs,用于存储当前学期课程列表
queue<VNode> vs;
/*if (choose == FAST)
{
// 如果选择快速学习,则每个学期最多可以上vexnum门课程
per_maxcourse = limit.max_class;
}
else
{
// 如果选择正常学习,则每个学期最多可以上vexnum/term门课程
per_maxcourse = vexnum / limit.term + 1;
// 如果每个学期可以上vexnum/term门课程,则每个学期最多可以上vexnum门课程
/*if (vexnum / limit.term < limit.term / 2)
{
per_maxcourse = vexnum / limit.term;
}
else
{
per_maxcourse = vexnum / limit.term + 1;
}
}*/
// 声明一个变量i,用于记录当前学期
int i;
// 遍历每个学期,尝试排列当前学期课程
for (i = 0; i < limit.term; i++)
{
// 声明一个vector,用于存储当前学期课程列表
vector<VNode> this_term_courses(vexnum);
// 如果已排列的门数等于vexnum,则表示排列完成
if (arranged_num == vexnum)
{
cout << "arranged_num == vexnum" << endl;
break;
}
// 声明一个变量course_num,用于记录本学期课程数
course_num = 0;
// 声明一个变量credit_sum,用于记录本学期课程的总学分
credit_sum = 0;
// 声明一个布尔变量flag,用于记录本学期是否存在当前考察课程的先修课程
flag = true;
cout << endl
<< "the " << i + 1 << " semester" << endl;
/*while (flag /*&& course_num < per_maxcourse)
{
while (p != NULL && flag)
{
for (int j = 0; j < course_num; j++)
{
if (p->adjvex == LocateVex(this_term_courses[j]))
{
flag = false;
break;
}
}
p = p->nextarc;
}*/
// 遍历当前学期课程列表
for (course = vexnum - 1; course >= 0; course--)
{
// 如果当前课程的编号为0,则表示该课程可以上
if (course_list[course] == 0)
{
// 遍历当前学期课程列表
for (int j = 0; j < course_num; j++)
{
q = this_term_courses[j].firstarc;
while (q && flag)
{
// 如果找到当前课程的先修课程,则将该课程的编号置为1,表示该课程不能上
if (q->adjvex == LocateVex(vex[course]))
{
flag = false;
break;
}
q = q->nextarc;
}
}
// 如果找到当前课程的先修课程,则将该课程的编号置为1,表示该课程不能上
if (!flag)
{
break;
}
// 打印当前课程的编号和课程信息
// cout << "vexnum:" << vexnum << endl
// << "arranged_num: " << arranged_num << endl;
cout << vex[course].data.classname << endl;
// 计算本学期课程的总学分
credit_sum += vex[course].data.credit;
// 将当前课程添加到当前学期课程列表中
this_term_courses[course_num] = vex[course];
// 将当前课程的编号置为1,表示该课程已选上
course_list[course] = 1;
// 将当前课程添加到队列中
vs.push(this_term_courses[course_num]);
// 打印添加到队列中的课程的编号和课程信息
// cout << "push into vs" << endl;
course_num++;
// 打印已排列的门数
arranged_num++;
// 打印本学期课程数
// cout << "semester_list[" << i << "]"
// << "++" << endl;
semester_list[i]++;
// 如果本学期课程的总学分加上准备考察课程的学分大于最大学分,则表示本学期课程已排列完毕
if (credit_sum + vex[course].data.credit > limit.max_credit)
{
course--;
}
}
}
// 打印本学期课程列表
// cout << endl
// << "the " << i + 1 << " semester" << endl;
}
// 如果已排列的门数不等于vexnum,则表示排列未完成
if (arranged_num != vexnum)
{
cout << "term:" << i << endl;
cout << "arranged_num:" << arranged_num << endl;
cout << "false!need more terms to finish the learning!" << endl;
return;
}
cout << "victory!" << endl;
// printToFile(vs);
// 打印文件头
// void printToFile(queue<VNode> vs)
//{
VNode n;
// 打印文件头
// cout << "vs.size()=" << vs.size() << endl;
string filename = "course.txt";
// 声明一个变量semester,用于记录当前学期
int semester, year;
semester = 1;
year = 2023;
// 打开文件
ofstream out(filename, ios::out);
// 打印文件头
for (; semester <= limit.term; semester++)
{
out << endl
<< "Courses for year " << year << " semester " << semester << ":" << endl
<< endl;
cout << endl
<< "Courses for year " << year << " semester " << semester << ":" << endl;
// 遍历课程,打印课程信息
// cout << "semester_list[semester]:" << semester_list[semester-1] << endl;
for (int k = 0; k < semester_list[semester - 1]; k++)
{
n = vs.front();
vs.pop();
// 打印当前课程的编号和课程信息
// cout << "k:" << k << endl;
cout << n.data.index << " " << n.data.classname << " " << n.data.credit << endl;
out << n.data.index << " " << n.data.classname << " " << n.data.credit << endl;
}
}
cout << endl
<< "the plan has been in '" << filename << "'" << endl;
cout << "you can look on your own " << endl;
out.close();
return;
}
ALGraph.h
#pragma once
#include <queue>
#include <vector>
// #include "LinkList.h"
#include "GraphInfo.h"
#ifndef ALGRAPH_H
#define ALGRAPH_H
#define MAX 1000
#define TERMNUMBER 6
#define CREDITMAX 10
class ALGraph
{
public:
int vexnum; // 顶点数目
int arcnum; // 弧数目
VNode vertices[MAX]; // 邻接表
public:
ALGraph();
~ALGraph();
VNode *getVertices();
void CreateGraph(int vnum, int anum, VNode data[], ArcInfo arcList[]); // 创建图
void addVex(VNode vex[], int prenum, int pre[], int postnum, int post[]);
void deleteVex(VNode vex);
void renewVex(VNode vex);
void DisGraph(); // 展示
VNode *Order_slow(); // 均匀分布
VNode *Order_fast(); // 紧凑分布
void change_Limit(); // 修改规则
void Arrange(VNode *vex, int choose);
void IndegreeCal(); // 统计每个顶点的入度
// void printToFile(queue<VNode> vs);
private:
int LocateVex(VNode v); // 根据顶点信息,返回顶点坐标
};
#endif
收尾
源码
已经传到仓库上了,
我的github仓库
我的gitee仓库https://gitee.com/aa2255/smalltask