有兩種方法:一種沒有學分排序,另一種考慮了學分排序,較推薦棧中排好序的方法,貪心更完全
測試數據文本:
C1 程序設計基礎 # 2
C2 離散數學 C1 3
C3 數據結構 C1,C2 4
C4 彙編語言 C1 3
C5 語言的設計和分析 C3,C4 2
C6 計算機原理 C11 3
C7 編譯原理 C3,C5 4
C8 操作系統 C3,C6 4
C9 高等數學 # 7
C10 線性代數 C9 5
C11 普通物理 C9 2
C12 數值分析 C1,C9,C10 3
#include<iostream>
#include<fstream>
#include<iomanip>
#define XQ_num 12 //最大學期數
#define Total_Book_num 100 //最大課程數
#define TRUE 1
#define ERROR 0
using namespace std;
struct Book //節點的數據類型
{
char Book_num[4]; //不能爲3,因爲會把後面的字符串也讀取進來
char Book_nam[20];
int study_Score;
int in_Degree; //指入度點的個數
int state; //標記是否已經修過這門課程
Book *next; //指先行課的地址
char book[40]; //先修課程字符串
int num; //記錄是第幾門課
int n; //記錄有幾門先行課
};
struct Build_Graph //用鄰接表的方法構建圖,數組的位置則是記錄該節點鄰接了所有得點
{
Book *graph;
int n; // int *length.....length數組的長度
void build_Graph(int n1) //課程的門數---(注意這個不能設爲構造函數,否則後面棧中的數據結構會引用這個數據結構沒有構造參數)
{
graph=new Book [n1]; //每個數組爲一門課程並且爲鄰接表的頭節點
//length=new int [n1]; //指頭節點每個鏈表的長度,同數組存儲
for(int i=0;i<n1;i++)
{
graph[i].next=NULL;
// length[i]=0; //記錄每門課的先行課的門數(未修的門數),不需要,用入度決定有幾門先行可
}
n=n1;
}
void Book_insert(Book p,int i) //插入每門要修的課程
{
graph[i]=p;
graph[i].num=i+1; //記錄是第幾門課,從第1門開始
graph[i].in_Degree=0;
graph[i].state=1; //如果狀態爲1時則是未被訪問過,0則表示是訪問過
graph[i].n=0;
}
void Build_Graph_insert(Book &p,int j,int n) //在j之後插入節點,在第n門課
{
Book *pp=&graph[n-1];
for(int i=1;i<j;i++)
pp=pp->next;
pp->next=&p;
graph[n-1].in_Degree++; //length[n]++;
}
void Fu_Zhi() //對每個變量進行賦值
{
int i;
for(i=0;i<n;i++)
{
Fenjie(graph[i].book,graph[i]);
}
}
void Fenjie(char a[],Book &c) //爲門課程建立鄰接表
{
char b[5];
int length=strlen(a);
int i=0,j=0,k=0;
while(i<length)
{
Book *t=new Book; //從第1門開始記錄
while(a[i]!=','&&a[i]!='#'&&i<length)
{
b[j]=a[i];
i++;j++;
}
if(a[i]=='#'){break;} //注意這裏存放的先後順序
b[j]='\0';
*t=graph[PiPei(b)-1]; //c[k]數組記錄每一門課程的先行課的數字型編號
(*t).next=NULL;
(*t).in_Degree=0;
k++; //
Build_Graph_insert(*t,k,c.num); //因爲是從自己本身開始算起,所以要從k+1門課後傳遞指針
if(a[i]==','){i++;j=0;continue;}
i++;j=0;
}
c.n=k;
}
int PiPei(char a[])
{
if(!strcmp(a,"C1")) return 1;
else
if(!strcmp(a,"C2")) return 2;
else
if(!strcmp(a,"C3"))return 3;
else
if(!strcmp(a,"C4"))return 4;
else
if(!strcmp(a,"C5"))return 5;
else
if(!strcmp(a,"C6"))return 6;
else
if(!strcmp(a,"C7"))return 7;
else
if(!strcmp(a,"C8"))return 8;
else
if(!strcmp(a,"C9"))return 9;
else
if(!strcmp(a,"C10"))return 10;
else
if(!strcmp(a,"C11"))return 11;
else
if(!strcmp(a,"C12"))return 12;
}
void display1() //輸出所有課程表的信息
{
cout<<setiosflags(ios::left);
cout<<setw(15)<<"課程編號"<<setw(30)<<"課程名稱"<<setw(20)<<"先決條件"<<"學分"<<endl;
cout<<"--------------------------------------------------------------------------------"<<endl;
for(int i=0;i<n;i++)
{
cout<<setw(15)<<graph[i].Book_num<<setw(30)<<graph[i].Book_nam<<setw(20)<<graph[i].book<<graph[i].study_Score<<endl;
}
}
void display2() //輸出鄰接表的函數
{
int i,j;
Book *t;
for(i=0;i<n;i++)
{
t=&graph[i];
if(graph[i].in_Degree==0)cout<<graph[i].Book_num<<endl;
else
cout<<graph[i].Book_num<<"-->";
for(j=1;j<=graph[i].in_Degree;j++)
{
t=t->next;
if(j==graph[i].in_Degree)cout<<t->Book_num<<endl;
else
{
cout<<t->Book_num<<"-->";
}
}
}
}
void Destory()
{
delete graph;
}
};
struct Stack //構造棧
{
Book *base;
int top;
int length; //記錄棧中數據的長度
//Build_Graph graph1;
//int sum1; //學期總數
//int top_score; //每個學期的學分上線
Stack(int n)
{
base=new Book [n]; ////因爲有多少門課是已經在Build_Graph結構中的n變量中包含,因爲最大的課程數爲total_booknum
top=-1;
length=0;
}
void Destory_Stack()
{
delete base;
}
void Clear_Stack()
{
top=-1;
length=0;
}
bool Test_Stack_Empty() //棧空爲true,不空爲false
{
if(top==-1)return true;
else return false;
}
Book Get_Top() //獲得棧頂元素並把棧頂元素輸出棧
{
top--;
length--;
return base[top+1];
}
int Get_Top_Study_Score()
{
int t;
t=base[top].study_Score;
return t;
}
void Push(Book p)
{
top++;
length++;
base[top]=p;
}
int Length_Stack()
{
return length;
}
};
void Topological_Sort(Stack s,Build_Graph g,int a) //a是總的課程數目
{
cout<<"--------------------------------------------------------------------------------"<<endl;
int sum,top_score,ii,i,j,k,average;
cout<<" 學期總數:";cin>>sum;
cout<<" 每學期的學分上線爲:";cin>>top_score;
if(sum>XQ_num){cout<<" 輸入的學期數超出了範圍!"<<endl; return ;}
if(top_score>Total_Book_num){cout<<" 輸入的課程數超出了範圍!"<<endl;return ;}
cout<<"--------------------------------------------------------------------------------"<<endl;
cout<<" 課程編排的結果爲:"<<endl;
cout<<"--------------------------------------------------------------------------------"<<endl;
average=a/sum;average+=1; //每個學期選的課數小於等於average
int count1=0,count2=0; //count1記錄學期的個數,第幾個學期,count2記錄等於average學期的個數
int sum_course=0;
for(ii=0;ii<sum;ii++) //有幾個學期就循環多少次
{
for(i=0;i<a;i++) //每個學期找入度爲0並且沒有被訪問過節點進棧
{
if((g.graph[i].in_Degree==0)&&(g.graph[i].state==1))
s.Push(g.graph[i]);
}
count1++;
Book *pp=new Book;
int sum_score=0; //記錄每個學期
int ss=0; //記錄每個學期選課的門數總的學分
cout<<"第"<<count1<<"個學期所選的課程爲: ";
while((!s.Test_Stack_Empty())&&(ss<average)&&((sum_score+s.Get_Top_Study_Score())<=top_score)&&(count2<average)) //安排一個學期的課程
{
pp=&s.Get_Top();
cout<<(*pp).Book_nam<<" ";
sum_course++;
g.graph[(*pp).num-1].state=0; //注意是原來的圖的入讀數-1
ss++;
sum_score+=(*pp).study_Score;
Book *p;
for(j=0;j<a;j++) //入度爲0的節點的後序節點的入讀-1
{
if(j==((*pp).num-1))continue;
int n=g.graph[j].in_Degree;
if(n!=0)
{
p=&g.graph[j];
for(k=0;k<(g.graph[j].n);k++) //找一個鏈表中相匹配的課程
{
p=p->next;
if((*pp).num==p->num){g.graph[j].in_Degree--;}
}
}
}
}
s.Clear_Stack();
if(ss==average)count2++;
cout<<endl;
}
if(sum_course==a)cout<<"課程編排成功!"<<endl;
else cout<<"課程編排失敗!"<<endl;
cout<<"--------------------------------------------------------------------------------"<<endl;
}
int main()
{
int total_booknum,n;
cout<<"--------------------------------------------------------------------------------"<<endl;
cout<<" 歡迎進入課程編排系統 "<<endl;
cout<<"--------------------------------------------------------------------------------"<<endl;
con:cout<<" 是否開始進行課程編排,是請按1,退出請按0:";
cin>>n;
while(n==1)
{
system("cls");
cout<<" 該專業開設的課程數:";cin>>total_booknum;
cout<<"--------------------------------------------------------------------------------"<<endl;
cout<<"輸入每門課的課程信息(文件的讀入)";
ifstream in("課程信息.txt");
if(!in)
{
cerr<<"打開文本-課程信息.txt-有誤!"<<endl;
exit(1);
}
Build_Graph Graph;
Graph.build_Graph(total_booknum);
int i;Book p;
for(i=0;i<total_booknum;i++)
{
in>>p.Book_num>>p.Book_nam>>p.book>>p.study_Score;
Graph.Book_insert(p,i);
}
in.close();
cout<<"要編排的課程信息如下(沒有先行課的先行課屬性爲#):"<<endl;
Graph.display1(); //課程信息的輸出
Graph.Fu_Zhi();
cout<<"--------------------------------------------------------------------------------"<<endl;
cout<<"課程的鄰接表(右邊爲該門課的先行課)爲:"<<endl;
Graph.display2();
Stack T_sort(total_booknum);
Topological_Sort(T_sort,Graph,total_booknum);
goto con;
}
if((n!=1)&&(n!=0)){cout<<"輸入的數據不符合,請重新輸入!"<<endl;goto con;}
return 0;
}
排序後:
#include<iostream>
#include<fstream>
#include<iomanip>
#define XQ_num 12 //最大學期數
#define Total_Book_num 100 //最大課程數
#define TRUE 1
#define ERROR 0
using namespace std;
struct Book //節點的數據類型
{
char Book_num[4]; //不能爲3,因爲會把後面的字符串也讀取進來
char Book_nam[20];
int study_Score;
int in_Degree; //指入度點的個數
int state; //標記是否已經修過這門課程
Book *next; //指先行課的地址
char book[40]; //先修課程字符串
int num; //記錄是第幾門課
int n; //記錄有幾門先行課
};
struct Build_Graph //用鄰接表的方法構建圖,數組的位置則是記錄該節點鄰接了所有得點
{
Book *graph;
int n; // int *length.....length數組的長度
void build_Graph(int n1) //課程的門數---(注意這個不能設爲構造函數,否則後面棧中的數據結構會引用這個數據結構沒有構造參數)
{
graph=new Book [n1]; //每個數組爲一門課程並且爲鄰接表的頭節點
//length=new int [n1]; //指頭節點每個鏈表的長度,同數組存儲
for(int i=0;i<n1;i++)
{
graph[i].next=NULL;
// length[i]=0; //記錄每門課的先行課的門數(未修的門數),不需要,用入度決定有幾門先行可
}
n=n1;
}
void Book_insert(Book p,int i) //插入每門要修的課程
{
graph[i]=p;
graph[i].num=i+1; //記錄是第幾門課,從第1門開始
graph[i].in_Degree=0;
graph[i].state=1; //如果狀態爲1時則是未被訪問過,0則表示是訪問過
graph[i].n=0;
}
void Build_Graph_insert(Book &p,int j,int n) //在j之後插入節點,在第n門課
{
Book *pp=&graph[n-1];
for(int i=1;i<j;i++)
pp=pp->next;
pp->next=&p;
graph[n-1].in_Degree++; //length[n]++;
}
void Fu_Zhi() //對每個變量進行賦值
{
int i;
for(i=0;i<n;i++)
{
Fenjie(graph[i].book,graph[i]);
}
}
void Fenjie(char a[],Book &c) //爲門課程建立鄰接表
{
char b[5];
int length=strlen(a);
int i=0,j=0,k=0;
while(i<length)
{
Book *t=new Book; //從第1門開始記錄
while(a[i]!=','&&a[i]!='#'&&i<length)
{
b[j]=a[i];
i++;j++;
}
if(a[i]=='#'){break;} //注意這裏存放的先後順序
b[j]='\0';
*t=graph[PiPei(b)-1]; //c[k]數組記錄每一門課程的先行課的數字型編號
(*t).next=NULL;
(*t).in_Degree=0;
k++; //
Build_Graph_insert(*t,k,c.num); //因爲是從自己本身開始算起,所以要從k+1門課後傳遞指針
if(a[i]==','){i++;j=0;continue;}
i++;j=0;
}
c.n=k;
}
int PiPei(char a[])
{
if(!strcmp(a,"C1")) return 1;
else
if(!strcmp(a,"C2")) return 2;
else
if(!strcmp(a,"C3"))return 3;
else
if(!strcmp(a,"C4"))return 4;
else
if(!strcmp(a,"C5"))return 5;
else
if(!strcmp(a,"C6"))return 6;
else
if(!strcmp(a,"C7"))return 7;
else
if(!strcmp(a,"C8"))return 8;
else
if(!strcmp(a,"C9"))return 9;
else
if(!strcmp(a,"C10"))return 10;
else
if(!strcmp(a,"C11"))return 11;
else
if(!strcmp(a,"C12"))return 12;
}
void display1() //輸出所有課程表的信息
{
cout<<setiosflags(ios::left);
cout<<setw(15)<<"課程編號"<<setw(30)<<"課程名稱"<<setw(20)<<"先決條件"<<"學分"<<endl;
cout<<"--------------------------------------------------------------------------------"<<endl;
for(int i=0;i<n;i++)
{
cout<<setw(15)<<graph[i].Book_num<<setw(30)<<graph[i].Book_nam<<setw(20)<<graph[i].book<<graph[i].study_Score<<endl;
}
}
void display2() //輸出鄰接表的函數
{
int i,j;
Book *t;
for(i=0;i<n;i++)
{
t=&graph[i];
if(graph[i].in_Degree==0)cout<<graph[i].Book_num<<endl;
else
cout<<graph[i].Book_num<<"-->";
for(j=1;j<=graph[i].in_Degree;j++)
{
t=t->next;
if(j==graph[i].in_Degree)cout<<t->Book_num<<endl;
else
{
cout<<t->Book_num<<"-->";
}
}
}
}
void Destory()
{
delete graph;
}
};
struct Stack //構造棧
{
Book *base;
int top;
int length; //記錄棧中數據的長度
//Build_Graph graph1;
//int sum1; //學期總數
//int top_score; //每個學期的學分上線
Stack(int n)
{
base=new Book [n]; ////因爲有多少門課是已經在Build_Graph結構中的n變量中包含,因爲最大的課程數爲total_booknum
top=-1;
length=0;
}
void Destory_Stack()
{
delete base;
}
void Clear_Stack()
{
top=-1;
length=0;
}
bool Test_Stack_Empty() //棧空爲true,不空爲false
{
if(top==-1)return true;
else return false;
}
Book Get_Top() //獲得棧頂元素並把棧頂元素輸出棧
{
top--;
length--;
return base[top+1];
}
int Get_Top_Study_Score()
{
int t;
t=base[top].study_Score;
return t;
}
void Push(Book p)
{
top++;
length++;
base[top]=p;
}
int Length_Stack()
{
return length;
}
void PX_MAX_MIN() //排序,從小到大
{
int i,j;Book t;
for(i=0;i<(length-1);i++)
{
int max=base[i].study_Score;
for(j=i+1;j<length;j++)
{
if(max<base[j].study_Score)
{
t=base[i];
base[i]=base[j];
base[j]=t;
}
}
}
}
};
void Topological_Sort(Stack s,Build_Graph g,int a) //a是總的課程數目
{
cout<<"--------------------------------------------------------------------------------"<<endl;
int sum,top_score,ii,i,j,k,average;
cout<<" 學期總數:";cin>>sum;
cout<<" 每學期的學分上線爲:";cin>>top_score;
if(sum>XQ_num){cout<<" 輸入的學期數超出了範圍!"<<endl; return ;}
if(top_score>Total_Book_num){cout<<" 輸入的課程數超出了範圍!"<<endl;return ;}
cout<<"--------------------------------------------------------------------------------"<<endl;
cout<<" 課程編排的結果爲:"<<endl;
cout<<"--------------------------------------------------------------------------------"<<endl;
average=a/sum;average+=1; //每個學期選的課數小於等於average
int count1=0,count2=0; //count1記錄學期的個數,第幾個學期,count2記錄等於average學期的個數
int sum_course=0;
for(ii=0;ii<sum;ii++) //有幾個學期就循環多少次
{
for(i=0;i<a;i++) //每個學期找入度爲0並且沒有被訪問過節點進棧
{
if((g.graph[i].in_Degree==0)&&(g.graph[i].state==1))
s.Push(g.graph[i]);
}
count1++;
Book *pp=new Book;
int sum_score=0; //記錄每個學期
int ss=0; //記錄每個學期選課的門數總的學分
cout<<"第"<<count1<<"個學期所選的課程爲: ";
s.PX_MAX_MIN();
while((!s.Test_Stack_Empty())&&(ss<average)&&((sum_score+s.Get_Top_Study_Score())<=top_score)&&(count2<average)) //安排一個學期的課程
{
s.PX_MAX_MIN();
pp=&s.Get_Top();
cout<<(*pp).Book_nam<<" ";
sum_course++;
g.graph[(*pp).num-1].state=0; //注意是原來的圖的入讀數-1
ss++;
sum_score+=(*pp).study_Score;
Book *p;
for(j=0;j<a;j++) //入度爲0的節點的後序節點的入讀-1
{
if(j==((*pp).num-1))continue;
int n=g.graph[j].in_Degree;
if(n!=0)
{
p=&g.graph[j];
for(k=0;k<(g.graph[j].n);k++) //找一個鏈表中相匹配的課程
{
p=p->next;
if((*pp).num==p->num){g.graph[j].in_Degree--;}
}
}
}
}
s.Clear_Stack();
if(ss==average)count2++;
cout<<endl;
}
if(sum_course==a)cout<<"課程編排成功!"<<endl;
else cout<<"課程編排失敗!"<<endl;
cout<<"--------------------------------------------------------------------------------"<<endl;
}
int main()
{
int total_booknum,n;
cout<<"--------------------------------------------------------------------------------"<<endl;
cout<<" 歡迎進入課程編排系統 "<<endl;
cout<<"--------------------------------------------------------------------------------"<<endl;
con:cout<<" 是否開始進行課程編排,是請按1,退出請按0:";
cin>>n;
while(n==1)
{
system("cls");
cout<<" 該專業開設的課程數:";cin>>total_booknum;
cout<<"--------------------------------------------------------------------------------"<<endl;
cout<<"輸入每門課的課程信息(文件的讀入)";
ifstream in("課程信息.txt");
if(!in)
{
cerr<<"打開文本-課程信息.txt-有誤!"<<endl;
exit(1);
}
Build_Graph Graph;
Graph.build_Graph(total_booknum);
int i;Book p;
for(i=0;i<total_booknum;i++)
{
in>>p.Book_num>>p.Book_nam>>p.book>>p.study_Score;
Graph.Book_insert(p,i);
}
in.close();
cout<<"要編排的課程信息如下(沒有先行課的先行課屬性爲#):"<<endl;
Graph.display1(); //課程信息的輸出
Graph.Fu_Zhi();
cout<<"--------------------------------------------------------------------------------"<<endl;
cout<<"課程的鄰接表(右邊爲該門課的先行課)爲:"<<endl;
Graph.display2();
Stack T_sort(total_booknum);
Topological_Sort(T_sort,Graph,total_booknum);
goto con;
}
if((n!=1)&&(n!=0)){cout<<"輸入的數據不符合,請重新輸入!"<<endl;goto con;}
return 0;
}