优化算法

时间:2019-03-24 17:35:27

标签: python

关于Uni大学的一门课程,我已经进行了练习。我的问题不是我无法解决问题,而是我的算法不够快。

作业

Josefine在整个暑假期间都决定自己想在算法大学学习哪些课程。一门课程需要一个学期才能完成(作为超级学生,她总是会成功)。有些课程取决于其他课程,因此不允许在同一学期修这些课程。如果课程i取决于课程j,那么约瑟芬必须在课程j之前的一个学期修读课程i。她希望在尽可能短的学期内完成学业。

鉴于Josefine要学习的N门课程(从1到N),并且它们各自依赖的课程,计算Josefine完成学习所需的最少学期数。 (同样,她是一名超级学生,因此她每学期可以参加无数课程)。

您可以假设Josefine选择的课程中没有循环依赖项。

输入格式

Line 1: The integers N and M, where N is the number of courses and M is the total number of dependencies.
Line 2..M+1: Two integers X and Y meaning the course X depends on the course Y (ie. course Y must have been completed before course X)

输出格式

Line 1: The fewest number of semesters Josefine needs to use.

我当前的代码

NM = input()
NM = NM.split(" ")
N = int(NM[0])
M = int(NM[1])

remCourses = []
courseRes = {}
for i in range(1,N+1):
    courseRes[str(i)] = list()
    remCourses.append(str(i))

for i in range(0,M):
    res = input()
    res = res.split(" ")
    courseRes[str(res[0])].append(str(res[1]))

semCount = 0
while len(remCourses) > 0:
    newCourses = []
    for key in courseRes:
        if len(courseRes[key]) == 0:
            newCourses.append(key)


    for l in range(1,N+1):
        for course in newCourses:
            if course in courseRes[str(l)]:
                courseRes[str(l)].remove(course)

    for course in newCourses:
        if course in remCourses:
            remCourses.remove(course)

    semCount += 1

print(semCount)

我的问题是代码不够快,无法获得所需的分数。非常感谢som的帮助。

预先感谢:)

1 个答案:

答案 0 :(得分:2)

您可以通过使用set操作更快地找到解决方案。

首先假定我们具有以下依赖性:

deps = [(11, 2), (11, 9), (8, 9), (11, 10), (3, 10),
        (5, 11), (7, 11), (7, 8), (3, 8)]

形成下图:

wikipedia dag

找到她在第一学期需要学习的课程:

semesters = []
sources = {start for start, end in deps}
sinks   = {end for start, end in deps}
semester = sources - sinks
semesters.append(semester)

即找到图中的所有根(没有任何传入箭头的节点)。

然后删除根:

deps = [(start, end) for start, end in deps if start not in semester]

然后重复...

semesters = []
while deps:
    sources = {start for start, end in deps}
    sinks   = {end for start, end in deps}
    semester = sources - sinks
    semesters.append(semester)
    deps = [(start, end) for start, end in deps if start not in semester]

print("semesters needed:", 1 + len(semesters))

我们需要添加1,因为最后一次删除根会删除2个级别的节点。

我们可以使用timeit模块来比较两个版本(我已经将您的代码放入函数中并修复了两个错误):

def semestercount():
    deps = [(11, 2), (11, 9), (8, 9), (11, 10), (3, 10),
            (5, 11), (7, 11), (7, 8), (3, 8)]
    count = 0
    while deps:
        sources = {start for start, end in deps}
        sinks   = {end for start, end in deps}
        semester = sources - sinks
        count += 1
        deps = [(start, end) for start, end in deps if start not in semester]
    return count + 1


def op_code():
    NM = [(11, 2), (11, 9), (8, 9), (11, 10), (3, 10),
          (5, 11), (7, 11), (7, 8), (3, 8)]
    nodes = list(set(sum(NM, ())))
    N = len(nodes)
    M = len(NM)
    remCourses = []
    courseRes = {}
    for i in range(N):
        courseRes[nodes[i]] = list()
        remCourses.append(nodes[i])

    for i in range(0,M):
        res = NM[i]
        courseRes[res[0]].append(res[1])

    semCount = 0
    while len(remCourses) > 0:
        newCourses = []
        for key in courseRes:
            if len(courseRes[key]) == 0:
                newCourses.append(key)


        for l in range(N):
            for course in newCourses:
                if course in courseRes[nodes[l]]:
                    courseRes[nodes[l]].remove(course)

        for course in newCourses:
            if course in remCourses:
                remCourses.remove(course)

        semCount += 1
    return semCount


import timeit
print timeit.timeit("semestercount()", "from __main__ import semestercount")
print timeit.timeit("op_code()", "from __main__ import op_code")

在我的计算机上打印:

5.85758427398
42.8849096743

那么快很多:-)