There are a total of n courses you have to take, labeled from 0
to n - 1
.
Some courses may have prerequisites, for example to take course 0 you have to first take course 1, which is expressed as a pair: [0,1]
Given the total number of courses and a list of prerequisite pairs, is it possible for you to finish all courses?
For example:
2, [[1,0]]
There are a total of 2 courses to take. To take course 1 you should have finished course 0. So it is possible.
2, [[1,0],[0,1]]
There are a total of 2 courses to take. To take course 1 you should have finished course 0, and to take course 0 you should also have finished course 1. So it is impossible.
Note:
The input prerequisites is a graph represented by a list of edges, not adjacency matrices. Read more about how a graph is represented.
- This problem is equivalent to finding if a cycle exists in a directed graph. If a cycle exists, no topological ordering exists and therefore it will be impossible to take all courses.
- Topological Sort via DFS - A great video tutorial (21 minutes) on Coursera explaining the basic concepts of Topological Sort.
- Topological sort could also be done via BFS.
有向图:
主要有深度优先和拓扑排序2中方法
1、拓扑排序,如果能够用拓扑排序完成对图中所有节点的排序的话,就说明这个图中没有环,而如果不能完成,则说明有环。
2、可以用Strongly Connected Components来做,我们可以回忆一下强连通子图的概念,就是说对于一个图的某个子图,该子图中的任意u->v,必有v->u,则这是一个强连通子图。这个限定正好是环的概念。所以我想,通过寻找图的强连通子图的方法应该可以找出一个图中到底有没有环、有几个环。
3、就是用一个改进的DFS
刚看到这个问题的时候,我想单纯用DFS就可以解决问题了。但细想一下,是不能够的。如果题目给出的是一个无向图,那么OK,DFS是可以解决的。但无向图得不出正确结果的。比如:A->B,A->C->B,我们用DFS来处理这个图,我们会得出它有环,但其实没有。
我们可以对DFS稍加变化,来解决这个问题。解决的方法如下:
图中的一个节点,根据其C[N]的值,有三种状态:
0,此节点没有被访问过
-1,被访问过至少1次,其后代节点正在被访问中
1,其后代节点都被访问过。
按照这样的假设,当按照DFS进行搜索时,碰到一个节点时有三种可能:
1、如果C[V]=0,这是一个新的节点,不做处理
2、如果C[V]=-1,说明是在访问该节点的后代的过程中访问到该节点本身,则图中有环。
该DAG的拓扑序列为A B C D或者A C B D
而此有向图是不存在拓扑序列的,因为图中存在环路
二.拓扑序列算法思想
(1)从有向图中选取一个没有前驱(即入度为0)的顶点,并输出之;
class Solution(object):
def canFinish(self, numCourses, prerequisites):
n = numCourses
p = prerequisites
v = [0] * n
dic = {}
indegree = [0] * n
graph = [[] for i in xrange(n)]#[[]] * n
for i,j in p:
graph[i].append(j)
#print graph
def check2(cur):
if v[cur] == -1:
return False
if v[cur] == 1:#如果访问到这儿,后面的节点之前都已经访问过了,没问题,所以等于一个剪枝的过程
return True
v[cur] = -1
#l = dic.get(cur,[])
for j in graph[cur]:
if not check2(j):
return False
v[cur] = 1
return True
for i in xrange(n):
if not check2(i):
return False
return True
'''
def check(cur):
if v[cur] == 1:
return True
v[cur] = 1
l = dic.get(cur)
if l != None:
for i in l:
if check(i):
return True
v[cur] = 0
return False
for i in p:
dic[i[0]] = dic.get(i[0],[]) + [i[1]]
indegree[i[1]] += 1
q = []
for i in xrange(len(indegree)):
if indegree[i] == 0:
q += i,
#print q
while q != []:
node = q.pop()
for i,j in p:
#print i,j,node
if i == node:
indegree[j] -= 1
if indegree[j] == 0:
q += j,
#print indegree
return sum(indegree) == 0
'''