c++ 图 教学编制实验

前言

学校的课程作业,存在一点小问题(课程均匀分布 Order_slow()部分 ),但也通过了。
最近有点忙,实在改不了,要是有大佬能指教一番,感激不尽。

实验要求

项目名称:教学计划编制系统
项目内容:
1.大学的每个专业都要制定教学计划。假设任何专业都有固定的学习年限,每学年包含两个学期,每个学期的时间长度和学分上限均相等。每个专业开设的课程都是确定的
2.课程在开设时间的安排上必须满足先修关系。每门课程有哪些先修课程是确定的,可以有任意多门,也可以没有。每门课恰好占一个学期。试在这样的前提下设计一个教学计划编制系统,该系统需要满足以下功能。
(1) 完成课程进修目录信息的读取。
(2) 完成课程进修目录信息的编辑,包括课程的增加,删除,信息修改等。
(3) 学生的教学计划学期为 6,每个学期的学分上限为 10 分,允许用户指定下列编排策略进行教
学计划的输出
1)使学生在各个学期中的负担尽量均匀;
2)使课程尽可能地集中在前几个学期中 若根据给定的条件问题无解,则报告适当信息;否则将教
学计划输出到用户指定的文件中
盘了几年的老图

流程

课程数据预设 课程信息修改 拓扑排序 选择方案

可行且满意
不可行
课程数据预设
课程编排
课程信息修改
选择方案
是否可行
结束
修改课程或方案
教学计划编制系统
课程预设
setClass
课程修改
添加课程
addVex
删除课程
deleteVex
恢复课程
renewVex
课程编排
均匀分布
Order_slow
早学早解放
Order_fast
选择方案
Arrange

成果(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

  • 16
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杀小白

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值