问题描述如下:
某学院有n门课程,(i,j)表示i是j的先行课,即课程i必须在课程j之前的学期开设。对任意给出的先行课集合S={(1,3),(2,4)......},至少需要安排多少个学期?给出每个学期所开的课程清单。
这是一个拓扑图,我用的是贪婪求解:
存储课程用的是邻接数组,存储已找到的点的结构用的是栈stack<int> ss,存储每个点入度用的是数组indegree[];每次在所有没有选择的顶点中选择一个顶点W,它没有这样的入边(V,W),其中V不在ss中;
每学期遍历一次,把所有存进栈里的点输出,即为当前学期所要开设的课程。更新indegree,清空栈,重复操作,直到所有的点已被输出;
以下是代码:
#include <stdlib.h> #include <stdio.h> #include <iostream> #include <stack> using namespace std; typedef struct { int x,y; }section;//用来存储用户输入的先行课 //用邻接数组的方法表示图 void methed(int n, section s[], int sn)//n是课程数量,s是用户输入的课程顺序,sn是s的长度 { int ss[n+2][n+2]; int i,j; int indegree[n+2];//存储每个点的入度 stack<int> store;//栈,存储每个学期的课程, int Count =0, sTop;//count用来控制学期,sTop是栈顶 for(i=0; i<=n; i++) { for(j=0; j<=n; j++) ss[i][j] = 0; indegree[i]=0;// 初始化 } for(i=1; i<=n; i++)///顶点从 1 开始计,第一次写的时候没注意从0开始n-1结束,导致后来内存越界,百思不得其解=。=; for(j=1; j<=n; j++) for(int k=0; k<=sn; k++) if(s[k].x==i&&ss[i][j]==0) { ss[i][j]=s[k].y; indegree[s[k].y]++;//计算入度,s[k]的每个元素只访问一次, s[k].x=0;//防止多次计算 } cout<<"建立的邻接矩阵为:"<<endl; for(i=1; i<=n; i++)/// { for(j=1; j<=n; j++) cout<<ss[i][j]; cout<<endl; }//主要部分 for(j=1; j<=n; j++) { for(i=1; i<=n; i++) if(indegree[i]==0)//把所有入度为0的点加入栈 { store.push(i); Count++;//每加一次记一次数 } //环的判断:当没有点可以加进去的时候,栈就是空的,而程序没有正常退出的话,就是里面有环 if(store.empty()) { cout<<"无法继续找出学期数,请检查输入的先行课序列是否有误!"; exit(1); } cout<<"第"<<j<<"个学期的课程:"; while(!store.empty()) { sTop=store.top(); store.pop(); cout<<sTop<<","; //然后从图里删除这些点,并将它们出度的点的入度减一 for(int k=1; k<=n; k++) { if(ss[sTop][k]!=0) indegree[ss[sTop][k]]--; //不用处理ss[sTop][k]=0的情况,因为indegree是从indegree[1]开始 indegree[sTop]++;//入度为0的点也要处理;不然会再次加入到栈里 } } cout<<endl; if(Count==n)//如果点处理完了 break; } }
主函数:
#include <iostream> #include <stdlib.h> #include "xian.h" using namespace std; int main() { int n,sn,pre,las; cout<<"课程总数"<<endl; cin>>n; cout<<"先输入的先行课对数量,再输入先行课的序列:"<<endl; cin>>sn; section s[sn];//={{1,3},{1,4},{3,4},{3,6},{2,4},{2,5},{5,6},{4,6}}; for(int i=0;i<sn;i++) { cin>>pre; s[i].x=pre; cin>>las; s[i].y=las; } methed(n,s,sn); return 0; }
测试:
这是其中一组测试数据对应main函数里面注释掉的那组数据。
结果。