⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 range_course.h

📁 根据大学四年的教学计划
💻 H
字号:
struct CourseType {
	char course_no[5];        //课程编号
	char course_name[100];    //课程名
    int period;               //学时数
    int term;				  //开课学期
    int indegree;             //入度
};

bool operator ==(const CourseType &first, const CourseType &second)
{
   return strcmp(first.course_no, second.course_no)==0;
}


bool operator !=(const CourseType &first, const CourseType &second)
{
   return strcmp(first.course_no, second.course_no)!=0;
}


template<int terms_num>                   //terms_num表示要排课的学期数
class Range_Course:Digraph<CourseType,1000>{
public:
	Range_Course(ifstream *file_in, ofstream *file_out);
	void read();  //从输入流中输入有关信息,以建立一个有向图
	//用拓扑排序方式进行排课
	void topological_order();
	void write(); //输出课表信息 
private:
	ifstream *infile;                    //输入流 
    ofstream *outfile;                   //输出流
	Extended_queue<int> q[terms_num+1];	 //对入度为0的结点缓冲队列
	//课表,下标分别表示:学期、节次、星期、课程名
	char course_table[terms_num+1][11][6][100];
    int course_num[terms_num+1];         //每学期的课程数
	int locate_vex(char course_no[]);    //重载定位顶点
	void readln();                       //跳行  
	char get_char();                     //从输入流中输入一有意义的字符  
	bool range(int num,int term,char course_name[]);//排课
	bool range_one(int &week_day,int term,char course_name[]);//排一天的1节课
	bool range_two(int &week_day,int term,char course_name[]);//排一天的2节课
	bool range_three(int &week_day,int term,char course_name[]);//排一天的3节课
	int find_one(int week_day,int term);//找查一天1节空课
	int find_two(int week_day,int term);//找查一天连续2节空课
	int find_three(int week_day,int term);//找查一天连续3节空课
	void write(char s[],int l);           //输出指定长度的字符串 
	char *decimal_to_chinese_char(int n,char *s); //用中文表示十进制数
};


template<int terms_num> 
Range_Course<terms_num>::Range_Course(ifstream *file_in, ofstream *file_out)
{
   infile = file_in;
   outfile = file_out;

   int i,j,k;
   for(i=1;i<=terms_num;i++)                     //学期数
	   for(j=1;j<=10;j++)                        //节次
		   for(k=1;k<=5;k++)                     //星期   
			   strcpy(course_table[i][j][k],""); //清空课表 

}


template<int terms_num> 
void Range_Course<terms_num>::read()
{   //从输入流中输入有关信息,以建立一个有向图
	char c;
	int i,n,v,w,course_total_num=0;
	CourseType course;
	char prio_course_no[5];  //先决课程号

	//下面为从输入流中输入各学期所开的课程数
	(*infile).seekg(0);
	c = get_char();
	while(c<'0'||c>'9'){  //查找数字开始的行
		if(c!='\n')readln();
		c = get_char();
	}
	(*infile).putback(c);
	for(i=1;i<=terms_num;i++){
		(*infile)>>n;
		course_num[i]=n;
		course_total_num+=n;
	}

	//下面为从输入流中输入各课程信息(建立图的顶点信息)
	(*infile).seekg(0);
	c = get_char();
	while(c!=EOF){
		while(c!=EOF&&c!='c'){  //查找以'c'开始的行
			if(c!='\n')readln();
			c = get_char();
		}
		if(c!=EOF){             //处理以'c'开始的行
			(*infile).putback(c);
			(*infile)>>course.course_no;
			(*infile)>>course.course_name;
			(*infile)>>course.period;
			(*infile)>>course.term;
			course.indegree=0;
			readln();
			if(insert_vex(course)!=success){
				cout<<"线性表溢出!"<<endl;
				exit(1);
			}
		}
		c = get_char();
	}

	//下面为从输入流中输入各课程先决条件信息(建立图的弧信息)
	(*infile).seekg(0);
	c = get_char();
	while(c!=EOF){
		while(c!=EOF&&c!='c'){  //查找以'c'开始的行
			if(c!='\n')readln();
			c = get_char();
		}
		if(c!=EOF){             //处理以'c'开始的行
			(*infile).putback(c);
			(*infile)>>course.course_no;
			(*infile)>>course.course_name;
			(*infile)>>course.period;
			(*infile)>>course.term;
			w=locate_vex(course.course_no);
			if(w==-1){
				cout<<"非法顶点!"<<endl;
				exit(1);
			}
  
			c=get_char();
			while(c=='c'){
				(*infile).putback(c);
				(*infile)>>prio_course_no;
				v=locate_vex(prio_course_no);  //表示有一条弧<v,w>
				if(v==-1){
					cout<<"非法先决条件!"<<endl;
					exit(1);
				}
				insert_arc(v,w);              //插入弧
				vertices[w].data.indegree++;  //顶点w入度加1  
				c=get_char();
			}
		}
		if(c!='\n')readln();
		c=get_char();
	}

	if(course_total_num!=vex_num()){
		cout<<"各学期所开课程总数与实际课程数不等!"<<endl;
		exit(1);
	}

}


template<int terms_num> 
void Range_Course<terms_num>::topological_order()
{	//用拓扑排序方式进行排课
    int term,m=0;   
	int i,j,size0,size_term,v,w;
	
	//建立入度为0顶点的队列q[0..terms_num]
	for(v=0;v<count;v++){  
		if(vertices[v].data.indegree==0)  
			if(q[vertices[v].data.term].append(v)!=success){
				cout<<"队列溢出!"<<endl;
				exit(1);
			}  //入度为0者进入相应学期的队列
	}


	//生成课表
	for(term=1;term<=terms_num;term++){
		size0=q[0].size();
		size_term=q[term].size();
		if(size0+size_term<course_num[term]){
			cout<<"排课时出现冲突!"<<endl;
			exit(1);
		}
		if(size_term>course_num[term]){
			cout<<"排课时出现冲突!"<<endl;
			exit(1);
		} 
		for(i=1;i<=size_term;i++){
			q[term].retrieve(v);
			q[term].serve();
			range(vertices[v].data.period,term,vertices[v].data.course_name);
			j=0;
			while(adj_vex(v,j++,w)==success){
				vertices[w].data.indegree--;
				if(vertices[w].data.indegree==0&&(vertices[w].data.term==0||vertices[w].data.term>term))
					q[vertices[w].data.term].append(w);
				else if(vertices[w].data.indegree==0&&(vertices[w].data.term>0||vertices[w].data.term<=term)){
					cout<<"排课时出现冲突!"<<endl;
					exit(1);
				}
			}
		}
		for(i=1;i<=course_num[term]-size_term;i++){
			q[0].retrieve(v);
			q[0].serve();
			range(vertices[v].data.period,term,vertices[v].data.course_name);
			j=0;
			while(adj_vex(v,j++,w)==success){
				vertices[w].data.indegree--;
				if(vertices[w].data.indegree==0&&(vertices[w].data.term==0||vertices[w].data.term>term))
					q[vertices[w].data.term].append(w);
				else if(vertices[w].data.indegree==0&&(vertices[w].data.term>0||vertices[w].data.term<=term)){
					cout<<"排课时出现冲突!"<<endl;
					exit(1);
				}
			}
		}
	}

}


template<int terms_num> 
void Range_Course<terms_num>::write()
{	//输出课表信息
	int term,i,week_day;
	char s[20],s_tem[20];
	for(term=1;term<=terms_num;term++){
		
		//显示表头
		(*outfile)<<"第"<<decimal_to_chinese_char(term,s_tem)<<"学期课表"<<endl;
		(*outfile)<<endl;
		
		//显示标题
		write("节次",8);
		for(i=1;i<=5;i++)
			write(strcat(strcpy(s,"星期"),decimal_to_chinese_char(i,s_tem)),18);
		(*outfile)<<endl<<endl;
		
		//显示课表内容
		for(i=1;i<=10;i++){
			write(strcat(strcat(strcpy(s,"第"),decimal_to_chinese_char(i,s_tem)),"节"),8);
			for(week_day=1;week_day<=5;week_day++)
				write(course_table[term][i][week_day],18);
			(*outfile)<<endl;

			if(i==2||i==7)(*outfile)<<endl<<"课间休息"<<endl<<endl;
			if(i==5)(*outfile)<<endl<<endl<<"午间休息"<<endl<<endl<<endl;
			if(i==10)(*outfile)<<endl<<"晚自习"<<endl<<endl;
		}

		//各课表之间以较多空行相隔
		(*outfile)<<endl<<endl<<endl<<endl<<endl<<endl;
	}
}


template<int terms_num> 
int Range_Course<terms_num>::locate_vex(char course_no[])
{	//重载定位顶点
	int position=0;
	CourseType course;
	strcpy(course.course_no,course_no);
	while(position<count && vertices[position].data!=course)position++;
	if(position<count)return position;   //定位成功
	else return -1;                      //定位失败
}


template<int terms_num> 
void Range_Course<terms_num>::readln()
{	//跳行   
	char c;
	while ((c = (*infile).peek()) != EOF && (c = (*infile).get()) != '\n');
}


template<int terms_num> 
char Range_Course<terms_num>::get_char()
{	//从输入流中输入一有意义的字符
	char c;
	while ((c = (*infile).peek()) != EOF && ((c = (*infile).get()) == ' '||c=='\t'));
	return c;
}


template<int terms_num> 
bool Range_Course<terms_num>::range(int num,int term,char course_name[])
{	//排课
	static int week_day=1; //要排课的星期
	int i;
	if(num==1){     //对1节课进行排课
		if(range_one(week_day,term,course_name)==false)return false;
		else{
			week_day=(week_day<4)?(week_day+2):(week_day+2-5);
			return true;
		};
	}
	else if(num%3==0){
		for(i=0;i<num/3;i++)
			if(range_three(week_day,term,course_name)==false)return false;
			else week_day=(week_day<4)?(week_day+2):(week_day+2-5);
		return true;
	}
	else if(num%3==1){
		for(i=0;i<num/3-1;i++)
			if(range_three(week_day,term,course_name)==false)return false;
			else week_day=(week_day<4)?(week_day+2):(week_day+2-5);
		for(i=0;i<2;i++)
			if(range_two(week_day,term,course_name)==false)return false;
			else week_day=(week_day<4)?(week_day+2):(week_day+2-5);
		return true;
	}
	else{
		for(i=0;i<num/3;i++)
			if(range_three(week_day,term,course_name)==false)return false;
			else week_day=(week_day<4)?(week_day+2):(week_day+2-5);
		if(range_two(week_day,term,course_name)==false)	return false;
		else{
			week_day=(week_day<4)?(week_day+2):(week_day+2-5);
			return true;
		}
	}
}


template<int terms_num> 
bool Range_Course<terms_num>::range_one(int &week_day,int term,char course_name[])
{	//排一天的1节课
	int i,k;
	for(k=0;k<5;k++){
		i=find_one(week_day,term);
		if(i==-1)
			week_day=(week_day<4)?(week_day+2):(week_day+2-5);
		else{
			strcpy(course_table[term][i][week_day],course_name);
			return true; 
		}
	}
	return false;
}


template<int terms_num> 
bool Range_Course<terms_num>::range_two(int &week_day,int term,char course_name[])
{	//排一天的2节课
	int i,k,week_day_tem;
	for(k=0;k<5;k++){
		i=find_two(week_day,term);
		if(i==-1)
			week_day=(week_day<4)?(week_day+2):(week_day+2-5);
		else{
			strcpy(course_table[term][i][week_day],course_name);
			strcpy(course_table[term][i+1][week_day],course_name);
			return true; 
		}
	}
	//将2节连续上的课分解为两个单独上的1节课
	week_day_tem=week_day;
	if(range_one(week_day_tem,term,"")==true&&range_one(week_day_tem,term,"")==true){
		range_one(week_day,term,course_name);
		range_one(week_day,term,course_name);
		return true;
	}
	return false;
}


template<int terms_num> 
bool Range_Course<terms_num>::range_three(int &week_day,int term,char course_name[])
{	//排一天的3节课
	int i,k,week_day_tem;
	for(k=0;k<5;k++){
		i=find_three(week_day,term);
		if(i==-1)
			week_day=(week_day<4)?(week_day+2):(week_day+2-5);
		else{
			strcpy(course_table[term][i][week_day],course_name);
			strcpy(course_table[term][i+1][week_day],course_name);
			strcpy(course_table[term][i+2][week_day],course_name);
			return true; 
		}
	}
	//将3节连续上的课分解为2节连续上的课与单独上的1节课
	week_day_tem=week_day;
	if(range_one(week_day_tem,term,"")==true&&range_two(week_day_tem,term,"")==true){
		range_one(week_day,term,course_name);
		range_two(week_day,term,course_name);
		return true;
	}
	return false;
}


template<int terms_num> 
int Range_Course<terms_num>::find_one(int week_day,int term)
{	//找查一天1节空课,返回有空的节次,返回-1表示课已排满
	int i;
	for(i=1;i<=8;i++)   //检查第1、3大节是否有空
		if((i<=2||(i>=6&&i<=7))&&strlen(course_table[term][i][week_day])==0)
			return i;
	for(i=1;i<=8;i++)   //检查第2、4大节是否有空
		if((i>=3&&i<=5||(i>=8))&&strlen(course_table[term][i][week_day])==0)
			return i;
	return -1;
}


template<int terms_num> 
int Range_Course<terms_num>::find_two(int week_day,int term)
{	//找查一天连续2节空课,返回连续2节课有空的第1节课的节次,返回-1表示课已排满
	if(strlen(course_table[term][1][week_day])==0&&strlen(course_table[term][2][week_day])==0)
		return 1;   //检查第1大节是否有空
	if(strlen(course_table[term][6][week_day])==0&&strlen(course_table[term][7][week_day])==0)
		return 6;   //检查第3大节是否有空
	if(strlen(course_table[term][3][week_day])==0&&strlen(course_table[term][4][week_day])==0)
		return 3;   //检查第2大节是否有空
	if(strlen(course_table[term][4][week_day])==0&&strlen(course_table[term][5][week_day])==0)
		return 4;   //检查第2大节是否有空
	if(strlen(course_table[term][8][week_day])==0&&strlen(course_table[term][9][week_day])==0)
		return 8;   //检查第4大节是否有空
	if(strlen(course_table[term][9][week_day])==0&&strlen(course_table[term][10][week_day])==0)
		return 9;   //检查第4大节是否有空
	return -1;
}


template<int terms_num> 
int Range_Course<terms_num>::find_three(int week_day,int term)
{	//找查一天连续3节空课,返回连续3节课有空的第1节课的节次,返回-1表示课已排满
	if(strlen(course_table[term][3][week_day])==0&&strlen(course_table[term][4][week_day])==0&&strlen(course_table[term][5][week_day])==0)
		return 3;   //检查第2大节是否有空
	if(strlen(course_table[term][8][week_day])==0&&strlen(course_table[term][9][week_day])==0&&strlen(course_table[term][10][week_day])==0)
		return 8;   //检查第3大节是否有空
	return -1;
}


template<int terms_num> 
void Range_Course<terms_num>::write(char s[],int l)
{	//输出指定长度的字符串 
	int i;
	(*outfile)<<s;
	for(i=0;i<l-strlen(s);i++)(*outfile)<<" ";
}


template<int terms_num> 
char *Range_Course<terms_num>::decimal_to_chinese_char(int n,char *s)
{	//用中文表示十进制数 
	char digital[11][3]={"〇","一","二","三","四","五","六","七","八","九","十"};
	s[0]='\0';

	if(n<0){
		strcat(s,"负");
		n=-n;
	}
	n=n%100;      //假设n最多是一个两位数
	if(n/10>1){
		strcat(s,digital[n/10]);
		strcat(s,digital[10]);
		if(n%10>0)
			strcat(s,digital[n%10]);
	}
	else if(n/10==1){
		strcat(s,digital[10]);
		if(n%10>0)
			strcat(s,digital[n%10]);
	}
	else strcpy(s,digital[n%10]);
	return s;
}


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -