这是我在工作中遇到的经典CS问题: 我有一个我需要加载的资源列表。每个资源都有一个它需要的约束列表,以便加载和加载时满足其他资源可能需要的其他约束。在示例中:资源X具有a,b,c作为约束,因此它只能在满足a,b和c时加载。当加载时,X满足资源Y所需的约束n和m,其也需要约束p以便加载,因此当另一个资源将加载并满足p约束时,Y将加载,并且反过来满足其他约束。 所有资源所需的约束列表是最终的,这意味着每个资源可能需要几个约束,并且几个资源可能需要每个约束。 此外,一个资源需要空约束才能加载因此必须首先加载。
好的,经过这么长的解释,这是我的问题: 如果我事先知道的是每个资源需要哪些约束但是(事先)知道资源一旦加载满足哪些约束,我怎样才能找到资源的最佳加载顺序?
希望我的解释足够明确...... 谢谢!
答案 0 :(得分:3)
修改强>
简单解决方案:
使用n个顶点(资源)和m个顶点(约束)创建一个二部图。 - O(n + m)
将约束保存在某些查找表数据结构中(即哈希表)。
每当资源需要该约束时,在资源顶点和约束顶点之间绘制边。
创建列表 L 资源,最初为空。 (这是加载资源的顺序)。
创建一组 R 资源,初始为空。 (这是当前可以添加的资源集)。 - O(1)
将具有0个约束的一个资源添加到 R 。 - O(1)
而 R 不为空:
{
从 R 获取一些资源 r - O(1)
将 r 添加到 L - O(1)
让 S 成为资源 r 在加载时满足的所有约束的集合。
S 中的Foreach约束 c 查找约束顶点并删除所有转到此顶点的链接。如果在链接的另一侧,没有更多链接(意味着资源顶点现在已准备好加载),请将该顶点添加到 R 。 - O(| S |)
}
总运行时间:O(n * | S |),其中| S |是单个资源满足的最大约束数。
答案 1 :(得分:1)
一种简单的算法,复杂度很低(O(n ^ 2 * m),其中n是资源数,m是资源约束数):
Set resourcesToLoad = ...
List loadingOrder = new List()
Set constraintsSatisfied = new Set()
while (!resourcesToLoad.empty) {
for (resource in resourcesToLoad) {
if (constraintsSatisfied.containsAll(resource.constraintsNeeded) {
resourcesToLoad.remove(resource);
loadingOrder.arr(resource);
constraintsSatisfied.addAll(resource.constraintsProvided)
break;
}
}
}
答案 2 :(得分:1)
如果每个资源以恒定时间Ta,Tb,Tc加载,并且此时间与订单计算相比足够长,则您的资源列表将以任何加载顺序的时间总和(Ta,Tb,Tc)加载。
如果订单计算时间很长,那么您的任务就是“快速找到没有不满足约束的元素”。我现在能想到的最佳算法仍然是O(N ^ 2),没有比“查找匹配元素之前的扫描列表”更好的。
答案 3 :(得分:1)
如Christian所述,资源和约束之间的关系定义了一个二分图。使用该图的简单方法是将其表示为从约束到需要约束的那些资源的映射(例如,哈希表)。另外,保持从资源到未满足约束数的映射以及满足所有约束的那些资源的列表。
如果我们假设初始关系是由从资源到约束列表的映射给出的,那么解决方案看起来应该是这样的:
# resource_constraints must be given as a mapping
# from resource to list of needed constraints
loaded_resources = [] # list of resources already loaded
pending_resources = [] # list of resources we can load, but haven't yet
constraint_resources = {} # mapping from constraints to resources needing them
number_unsatisfied = {} # mapping from resources to number of unsatisfied constraints
for r in resource_constraints:
constraints = resource_constraints[r]
if not constraints:
pending_resources.append(r)
else:
number_unsatisfied[r] = len(constraints)
for c in constraints:
if c not in constraint_resources:
constraint_resources[c] = []
constraint_resources[c].append[r]
assert len(pending_resources) > 0, "Must be at least one unconstrained resource"
while pending_resources:
r1 = pending_resources.pop()
loaded_resources.append(r1)
for c in resource_constraints[r1]:
if c in constraint_resources:
for r2 in constraint_resources[c]:
number_unsatisfied[r2] -= 1
if number_unsatisfied[r2] == 0:
del number_unsatisfied[r2]
pending_resources.append(r2)
del constraint_resources[c]
assert len(loaded_resources) == len(resource_constraints), "Must load all resources"
以上是Python,编写为仅使用简单的功能作为伪代码。
采用这种方法,总运行时间为O(m1 + m2),其中m1是资源所需约束数的总和,m2是资源提供的约束数之和; m1可以提前确定,但m2直到运行时才知道。
答案 4 :(得分:0)
构建一个表示依赖关系的树,并加载深度优先遍历树所返回的资源(反向)。
从维基百科中查看this image ...您应该加载资源的顺序是12,11,10等等......当然还有替代方案。