随笔-课程表问题

  • 前置课程问题(课程表)
  • AOV网络
  • 拓扑排序
  • 广度优先搜索(BFS)
  1. 一些课程的学习要求有先修课程,有些则不需要,没有先后顺序的课程就可以并行学习(进行);

课程先修情况

  1. 在有向图中,有向边<Vi, Vj>表示活动Vi先于活动Vj进行,这种以顶点表示活动的有向图叫做AOV网络(Activity On Vertices)。 AOV中不能出现某项活动以自身作为先决条件的有向环(死循环)。

  2. 拓扑排序是把构成AOV网络的各个顶点排列成一个线性有序序列(按照前驱后继关系),他的一般过程:

    (1) 按照给定关系构造顶点的邻接表;

    (2) 设置数组in_degrees记录各顶点入度(前驱顶点个数),设置队列Q组织所有入度为0的顶点(无前驱顶点,这些顶点无先后关系,可以并行执行);

    (3) 从0度队列弹出顶点(删0入度点),逐步遍历与它连接的端点,并将这些端点的入度减一(断边); 如果端点的入度减为0,则将端点压入0度队列;

    重复上述步骤,直到:

    全部顶点输出,拓扑有序序列形成;

    图中有未输出的点,但跳出了循环,说明AOV网络存在有向环。

  3. 拓扑排序的实质是广度优先搜索,它是一个按照与零入度顶点相连的顶点逐一去搜索的。广度优先搜索是一个逐层遍历的过程,它将满足条件的初始顶点放入一个队列,然后逐个弹出(删点,FIFO),然后遍历所有与该顶点相连的端点(删边),队列中的每一个顶点就是一个层次的开端。

课程表问题的一个可行序列(python描述):

flat = lambda L: sum(map(flat, L), []) if isinstance(L, list) else [L]

# 拓扑排序
def topo_sort(courses, n):
    # 构建图的邻接表
    graph_adj = {}
    # 元素入度表,默认为0
    in_degrees = {x:0 for x in set(flat(courses))}
    for x in courses:
        if x[1] not in graph_adj:
            graph_adj[x[1]] = [x[0]]
        else:
            graph_adj[x[1]].append(x[0])
        in_degrees[x[0]] = in_degrees[x[0]] + 1

    queues = []
    for x in in_degrees:
        if in_degrees[x] == 0:
            queues.append(x)

    cnt = 0
    ret = []
    while queues:
        top = queues.pop(0)
        ret.append(top)
        cnt += 1
        if top not in graph_adj:
            continue
        for succ in graph_adj[top]:
            in_degrees[succ] -= 1
            if in_degrees[succ] == 0:
                queues.append(succ)
    if cnt == n:
        return ret
    else:
        return []


courses = [
    ['C3', 'C1'], ['C3', 'C2'],
    ['C4', 'C3'], ['C4', 'C2'],
    ['C5', 'C2'],
    ['C6', 'C5'], ['C6', 'C4'],
    ['C7', 'C4'], ['C7', 'C9'],
    ['C8', 'C1'],
    ['C9', 'C8']
]
# 程序调用
print(topo_sort(courses, 9))

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值