Algorithm 打印安装软件包所需的最小软件包集

Algorithm 打印安装软件包所需的最小软件包集,algorithm,data-structures,graph,dependencies,packages,Algorithm,Data Structures,Graph,Dependencies,Packages,我必须创建一个表示包之间依赖关系的数据结构 我想我可以简单地使用一个图表,但问题是一些软件包可能依赖于其中一个“可选”软件包,我们必须选择其中哪一个最适合安装(基本上,从这些可选选择中,我们需要安装最好的) 例如,假设我有以下情况: 包装1: 包装2:包装1 包装3:包装1,包装2 包装4:包装1 |包装3 包装5:包装1,包装2 |包装3 这种情况意味着: 包1没有依赖项 包2依赖于包1(我们需要安装包1) 包3依赖于包1和包2(我们需要同时安装这两个) 软件包4依赖于软件包1或3(我们可以安

我必须创建一个表示包之间依赖关系的数据结构

我想我可以简单地使用一个图表,但问题是一些软件包可能依赖于其中一个“可选”软件包,我们必须选择其中哪一个最适合安装(基本上,从这些可选选择中,我们需要安装最好的)

例如,假设我有以下情况:

  • 包装1:
  • 包装2:包装1
  • 包装3:包装1,包装2
  • 包装4:包装1 |包装3
  • 包装5:包装1,包装2 |包装3
  • 这种情况意味着:

  • 包1没有依赖项
  • 包2依赖于包1(我们需要安装包1)
  • 包3依赖于包1和包2(我们需要同时安装这两个)
  • 软件包4依赖于软件包1或3(我们可以安装1或3,但我们需要选择最佳的选择,这意味着我们需要做出选择 包4(依赖较少的包)
  • 包5取决于包1,也取决于包2或包3(同样,我们需要选择最佳选择)
  • 现在,问题显然是我们何时可以在不同的软件包之间进行选择

    我们如何选择它们

    例如,为什么包4应该依赖于包1而不是包3

    我们可以尝试检查包1和包3所依赖的包,但是如果我们有10000个选择,但我们只需要一个最佳选择,那又如何呢?它将需要数千个循环和太复杂的东西。可能有一些简单的事情,但我不知道是什么


    这种试图选择哪个更好安装的方法似乎导致了某种递归算法,这已经让我大吃一惊。

    我们可以将其建模为伪布尔优化问题


    假设有
    k个
    包。定义k个布尔变量
    x_i
    ,其中
    x_i
    为真,当且仅当最终选择安装软件包时。因此,目标是最小化
    x_i
    的总和,其中1可以创建具有两种类型节点的有向图:

    • 节点,其子节点使用AND逻辑组合
    • 节点,其子节点使用OR逻辑组合
    从一个节点开始的所有弧表示其依赖关系

    对于您的示例,这将创建以下图表:

    如果必须评估包的最小依赖集,可以使用深度优先搜索算法访问图形:

    • 当您访问一个
      节点时,您要计算其子节点的依赖项的总数
    • 当您访问<代码>或节点时,您可以考虑其子节点的最小依赖数量。
    示例代码

    下面是一个如何在python中实现这一点的示例(我使用了python,因为它的语法几乎类似于伪代码;您应该能够了解它的要点):

    #/usr/bin/env蟒蛇3
    课程包:
    #建造师
    定义初始化(自身、名称、依赖项):
    self.name=名称
    self.dependencies=set(依赖项)
    #需要打印包裹吗
    定义(自我):
    返回self.name
    #此方法返回此包的最佳依赖项集
    def getOptimalDependencies(自):
    optimalDependencies=set()
    对于self.dependencies中的依赖项:
    optimalDependencies=optimalDependencies.union(dependency.getOptimalDependencies())
    添加(自我)
    返回最优性依赖项
    类别或名称:
    #建造师
    定义初始化(自,依赖项):
    self.dependencies=set(依赖项)
    #此方法返回最佳的依赖项集
    #与此“或”组合的包的
    def getOptimalDependencies(自):
    optimalDependencies=set()
    对于self.dependencies中的依赖项:
    alternativeDependencies=dependency.getOptimalDependencies()
    如果len(最佳依赖项)=0或len(可选依赖项)
    然后,您可以创建示例的包,如下所示:

    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])])
    
    要获取包5的最佳依赖项列表,您可以调用包5.getOptimalDependencies()

    如果我们将其打印为:

    print(','.join(map(str, package5.getOptimalDependencies())))
    
    我们得到:

    package2,package1,package5
    

    如果你有依赖循环,你必须为它插入一些控件。

    我已经用python添加了一些代码来说明这个想法。然后,您可以用自己选择的语言重新实现。该算法可以通过避免每次访问包的节点时重新计算包的依赖关系来改进,但我选择保持代码的简单性,以便更易于阅读为什么
    getoptimerationdependencies
    方法应该找到最短路径?为什么我不明白为什么…你可以用归纳法来证明。您知道每个叶节点的最佳依赖项集(那些没有传出弧的节点,因此没有依赖项)。如果您知道给定节点的每个子节点的最佳依赖关系,那么您就知道该节点的最佳依赖关系:对于
    节点,它将是其子节点依赖关系的并集;对于
    节点,它将是其子节点依赖关系中最小的一组。我们基本上是从图的叶子开始访问图,然后一直访问我们想要查找其依赖关系的节点。您的函数有一个问题(通常的解决方案)。假设我们有以下情况:
    A:B | C,D | E
    <代码>B:G,H,M
    <代码>C:K,N
    <代码>D:G,H,M<代码>E:L,J。如果我们运行您的算法,它将为pa返回错误的答案
    (1 - x_5) + x_2 + x_3 >= 1
    
    x_k
    
    x_k = 1
    
    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])])
    
    print(','.join(map(str, package5.getOptimalDependencies())))
    
    package2,package1,package5