我正在尝试构建如下所示的数据树,我需要一个可以执行以下操作的高效匹配算法。
您可以将此树视为参加课程的先决条件列表。例如,course1具有先决条件3和4,而课程3具有先决条件7和8.如果想要参加课程1,他/她必须同时参加3和4,或者课程3或课程4的所有先决条件(因此如果他/她采取7,8,4,相当于3和4)。
现在一个孩子来了,说他想参加课程2,前提是他提前8,9和6课程。如何快速检查他是否符合条件?
我现在能想到的唯一方法是构建一个包含所有先决条件组合的查找表,并检查它以查找匹配项。但是,随着树变得越来越大(我正在尝试构建一个可能> 10,000个节点的树),这种方法会炸毁我的计算机。
有人对此有任何建议吗?或者更好的是,是否有一个定义明确的搜索算法可以处理这类任务? 提前致谢。 吉姆
图:一些任意数据树
答案 0 :(得分:1)
以简单的方式执行此操作可能会很好。如果学生想要2,首先检查它们是否满足5
先决条件规定的要求,然后检查它们是否满足6
先决条件规定的要求。您的需求检查功能将涉及递归调用或类似操作。
如果由于某种原因(图表中的周期?)不起作用,你可以向另一个方向走向你所描述的内容:从学生已经开始的课程开始,然后填充以获得学生有资格获得的所有课程列表。检查目标是否在该列表中(或者更确切地说:如果在构建列表时遇到目标,则立即停止。)
由于您不仅仅是遵循箭头,因此洪水填充有点复杂:我可以通过四种不同方式获得1
资格:(3 or (7 and 8)) and (4 or 9)
。但基本的想法是一样的:继续测试我的可达节点的父节点,看看我是否可以在我的集合中添加任何内容,直到我再也不能。
适用于这两种方法:我不完全清楚规则是什么,这是否“满足3而不是3的先决条件”是否具有传递性。给出:
1
/ \
2 3
/
4
/ \
5 6
我认为让(5,6)
符合我2
的资格,(5,6,3)
是否有资格获得1
?
如果是这样,那么我认为这个过程有点容易,因为作为一个简化的假设,我可以假装如果我已经(5,6)
,那么我也采取了4
,这个问题“我有资格获得2分吗?”变成了,“我有2个人吗?”。
在我看来,如果没有,我觉得更明智,因为我不认为我可以真正参加一大堆小学课程,然后直接进入10级以上的研究生工作。然后我学习的课程与我已经学过的先修课程之间存在功能差异。需要跟踪这种差异。在泛洪填充的情况下,我认为这意味着每个节点需要考虑2个标志,而不是1.在需求检查功能的情况下,我认为这意味着您需要进行2次检查(直接和间接满意),以及不需要递归。
答案 1 :(得分:0)
“(所以如果他/她拿下7,8,4,则相当于花了3和4)。” - 原始海报
这不是先决条件;普通类不像这样运行。这是一个可能的替换列表。例如,你想拥有一个2,但你也可以获得2的所有替换,即5,6。你可以进一步用9,10代替5,或用11代替6。
这是可替代性的递归定义。
在python中:
def canMake(desired, withIngredients):
if desired in withIngredients:
return True
else:
return all(canMake(s,withIngredients) for s in desired.substitutions)
旁注:
您需要能够在O(1)时间内查询节点的父节点。如果您将类定义为:
,这样可以正常工作2 requires 5,6
5 requires 9,10
...
如果您将其存储为:
,则需要添加反向引用5 allows 2
6 allows 2
9 allows 4,5
我们假设第一种情况course.prereqs
是必需类的列表(在第二种情况下,您可以通过为每个课程定义:course.parents = []
轻松构建此列表,然后附加{{1}每个课程的孩子)。
答案 2 :(得分:0)
直观的是通过BFS或DFS遍历树。
每当您到达表示已经开始的课程的节点时,请剪切该节点下的所有节点。
因此,只有两种情况下资格审查失败: