1 拓扑排序
拓扑排序主要是对有向无环图(DAG)进行拓扑排序。
上图就是一个有向无环图,有向无环图常用来描述一个工程或系统的进行过程(通常把计划,施工,生产,程序流程等当成是一个工程)
一个工程可以分为若干个子工程,只要完成了这些子工程(活动),就可以导致整个工程的完成。
有向无环图有两个应用:
AOV网(解决拓扑排序):用一个有向图表示一个工程的各子工程及其相互制约的关系,其中以顶点表示活动,弧表示活动之间的相互制约关系,称这种有向图为顶点表示的网。简称AOV网。
AOE网(解决关键路径):用一个有向图表示一个工程的各子工程及其相互制约的关系,其中以弧表示活动,顶点表示活动之间的开始或结束事件,称这种有向图为边表示活动的网。简称AOE网。
拓扑排序:在AOV网没有回路的前提下,我们将全部活动排列成一个线性序列,使得若AOV网中有弧<i,j>存在,则在这个序列中,i一定排在j的前面,具有这种性质的线性序列称为拓扑有序序列,相应的拓扑有序排序的算法就称为拓扑排序。
方法:
1、在有向图中选一个没有前驱的顶点且输出
2、从图中删除该顶点和所有以它为尾的弧
3、重复上述两步,直到全部顶点均已输出;或者当图中不存在无前驱的顶点为止。(所以拓扑排序也可以检查图中是否有环)。
对于一个有向无环图,我们发现c1和C9是没有前驱节点的,所以任选一个,C1,随后删除该顶点和所有以它为尾的弧,如下图。
最后,重复这个过程,得到其拓扑排序为 C1 C2 C3 C4 C5 C7 C9 C10 C11 C6 C12 C8
2 课程表
你这个学期必须选修 numCourse 门课程,记为 0 到 numCourse-1 。
在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们:[0,1]
给定课程总量以及它们的先决条件,请你判断是否可能完成所有课程的学习?
这里给出两个概念:图的入度和出度
入度就是:有向图的某个顶点作为终点的次数和。
出度就是:有向图的某个顶点作为起点的次数和。
思路:这个题一看就是遍历问题(能否学习完所有课程),就想到bfs,按照拓扑排序的思想,先将入度为0的节点删除,随后删除这个节点的所有出边,在循环。重点是我们要怎么初始化这个图,我们可以生成对应每个节点的入度和出边,然后套用bfs的模板就ok了。最后判断是可以学习完整个课程是利用一个count变量,我们在bfs时,每遍历一个元素,count++,最后判断count==numCourses。
class Solution {
public:
bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
/*
在每一个[1,0]中,prerequisite[0]是目的节点,prerequisite[1]是出发节点,
记录每个节点的出度边
记录每个节点的入度
然后进行bfs
*/
map<int,vector<int>> outedges;
map<int,int> degree;
for(auto prerequisite:prerequisites)
{
outedges[prerequisite[1]].push_back(prerequisite[0]);//记录每个节点的出度边
degree[prerequisite[0]]++;
}
int count=0;
queue<int> q;
//将所有节点中,度为0的节点入队
for(int i=0;i<numCourses;i++)
{
if(degree[i]==0)
q.push(i);
}
while(!q.empty())
{
int tmp=q.front();
q.pop();
count++;
for(auto next:outedges[tmp])
{
degree[next]--;
if(degree[next]==0)
q.push(next);
}
}
return count==numCourses;
}
};