我必须创建一个表示包之间依赖关系的数据结构。
我以为我可以简单地使用图表,但问题是某些软件包可能依赖于其中一个"可选"包,我们必须选择哪一个最优的包更方便安装(基本上,从这些可选的选择,我们需要安装最好的)。
例如,假设我有以下情况:
- 包1:
- package2:package1
- package3:package1,package2
- package4:package1 |包装3
- package5:package1,package2 |包装3
醇>
这种情况意味着:
- 包1没有依赖关系。
- 包2取决于包1(我们需要安装包1)。
- 包3取决于包1和2(我们需要同时安装)
- 包4取决于包1或3(我们可以安装1或3,但我们需要选择最佳选择,这意味着选择 包4依赖于较少的包裹)
- 包5取决于包1,它也取决于包2或3(再次,我们需要选择最佳选择)
醇>
现在,当我们可以在不同的包之间进行选择时,问题显而易见。
我们如何选择它们?
为什么,例如,包4应该依赖于包1而不是3?
我们可以尝试检查包1和包3所依赖的包,但是如果我们有10000个选择呢,但我们只需要1个最佳选择?它需要数千个循环和太复杂的东西。可能有些简单,但我不知道是什么。
这种尝试选择哪一个更好的安装似乎导致了递归算法somhow,这已经让我大吃一惊。
答案 0 :(得分:1)
您可以使用两种类型的节点创建有向图:
package
个节点,其子节点使用AND逻辑OR
个节点,其子节点使用OR逻辑组合从节点开始的所有弧代表其依赖关系。
对于您的示例,这将创建以下图表:
如果必须评估包的最小依赖关系集,可以使用深度优先搜索算法访问该图:
package
节点时,您可以对其子节点的依赖项数进行求和OR
节点时,您会考虑其子节点的最小依赖项数示例代码
这是一个如何在python中实现它的例子(我使用python,因为它的语法几乎就像伪代码;你应该能够得到它的要点):
#!/usr/bin/env python3
class Package:
# Constructor
def __init__(self, name, dependencies):
self.name = name
self.dependencies = set(dependencies)
# Needed to print the package
def __str__(self):
return self.name
# This method returns the optimal set of dependencies for this package
def getOptimalDependencies(self):
optimalDependencies = set()
for dependency in self.dependencies:
optimalDependencies = optimalDependencies.union(dependency.getOptimalDependencies())
optimalDependencies.add(self)
return optimalDependencies
class Or:
# Constructor
def __init__(self, dependencies):
self.dependencies = set(dependencies)
# This method returns the optimal set of dependencies
# of the packages combined with this 'OR'
def getOptimalDependencies(self):
optimalDependencies = set()
for dependency in self.dependencies:
alternativeDependencies = dependency.getOptimalDependencies()
if len(optimalDependencies) == 0 or len(alternativeDependencies) < len(optimalDependencies):
optimalDependencies = alternativeDependencies
return optimalDependencies
然后,您可以创建示例的包:
package1 = Package("package1", [])
package2 = Package("package2", [package1])
package3 = Package("package3", [package1, package2])
package4 = Package("package4", [Or([package1, package3])])
package5 = Package("package5", [package1, Or([package2, package3])])
要获取package5
的最佳家属列表,您可以拨打package5.getOptimalDependencies()
。
如果我们打印它:
print(','.join(map(str, package5.getOptimalDependencies())))
我们得到:
package2,package1,package5
如果你有依赖循环,你必须插入一些控件。
答案 1 :(得分:0)
我们可以将其建模为伪布尔优化问题。
假设有k
个包裹。定义k个布尔变量x_i
,其中x_i
为真,当且仅当最终选择是安装package_i时。因此,目标是最小化x_i
的总和,其中1 <= i <= k。如果每个包需要不同的“成本”来安装(例如,包大小),您可以最小化x_i
的加权和。
为了对约束“package5:package1,package2 | package3”进行建模,我们可以发现“package5已安装”暗示“已安装package1”。如果伪布尔优化器支持Conjunctive normal form中表示的约束,那么它可以写为
(!x_5 + x_1)
如果只允许线性不等式,则
(1 - x_5) + x_1 >= 1
另一半,“package5已安装”暗示“package2和/或package3已安装”,可写为
(!x_5 + x_2 + x_3)
或
(1 - x_5) + x_2 + x_3 >= 1
最后,您必须断言所需的包裹。
x_k
或
x_k = 1
现在我们已将问题建模为伪布尔优化问题,您可以调用任何可用的解算器并解决它。你可以参考Pseudo Boolean Competition获得最先进的求解器。