如何遍历具有特定属性的树

时间:2013-07-13 00:23:13

标签: python algorithm tree depth-first-search

我有一棵树,如下所示。

  • 红色表示它具有某种属性,未填充意味着它没有它。我想最小化Red检查。
    1. 如果Red比所有祖先还Red(并且不应再次检查)。
    2. 如果Not Red比所有后代都Not Red
  • 树的深度为d
  • 树的宽度为n
  • 请注意,子节点的值大于父节点。

    • 示例:在下面的树中,
      • 节点'0'有子节点[1,2,3],
      • 节点'1'有子节点[2,3],
      • 节点'2'有子节点[3]和
      • 节点'4'有子女[](没有孩子)。
    • 因此,儿童可以被构建为:

      if vertex.depth > 0:
          vertex.children = [Vertex(parent=vertex, val=child_val, depth=vertex.depth-1, n=n) for child_val in xrange(self.val+1, n)]
      else:
          vertex.children = []
      

这是一个示例树:

The tree

我正在尝试计算Red个节点的数量。树的深度和宽度都很大。所以我想做一种Depth-First-Search并另外使用上面的属性1和2.

如何设计算法来遍历该树?

PS:我标记了这个[python],但算法的任何轮廓都可以。

更新&背景

  1. 我想尽量减少财产检查。
  2. 属性检查是检查从我的树路径构造的二分图的连通性。 实施例
    • 示例树中的左下角节点有路径 = [0,1]。
    • 让二分图设置RC,其大小为rc。 (注意,树的宽度是n=r*c)。
    • 路径开始,我从一个完整的图形开始,然后删除路径中所有值的边(x,y),从而得到图的边缘:x, y = divmod(value, c)
  3. 属性检查的两个规则来自图的连通性: - 如果图形连接边缘[a,b,c]已移除,则它也必须与[a,b]移除(规则1)连接。 - 如果图形断开,边缘[a,b,c]被移除,那么它也必须断开连接边缘d去除[a,b,c,d](规则2)。

    更新2

    所以我真正想做的是检查从[0..n]中挑选d个元素的所有组合。树结构有点帮助,但即使我得到了一个最优的树遍历算法,我仍然会检查太多的组合。 (我刚才注意到了。)

    让我解释一下。假设我需要检查[4,5](所以4和5从二分图中删除,如上所述,但这里不相关。)。如果这是“红色”,我的树将阻止我仅检查[4]。那很好。但是,我也应该检查[5]。

    如何更改树的结构(可能是图表?)以进一步减少检查次数?

3 个答案:

答案 0 :(得分:2)

使用删除 - 收缩算法的变体来评估Tutte多项式(在(1,2)处评估,给出生成子图的总数)在完整的二分图K_ {r,c}上。

在一个句子中,想法是任意排序边缘,枚举生成树,并为每个生成树计算大小为r + c + k的生成子图有多少具有最小生成树。生成树的枚举是递归执行的。如果图G只有一个顶点,则关联的生成子图的数量是该顶点上的自循环数选择k。否则,找到G中不是自循环的最小边,并进行两次递归调用。第一个是图表G / e,其中e是缩小的。第二个是图G-e,其中e被删除,但只有连接了G-e。

答案 1 :(得分:1)

Python足够接近伪代码。

class counter(object):
    def __init__(self, ival = 0):
        self.count = ival

    def count_up(self):
        self.count += 1
        return self.count

def old_walk_fun(ilist, func=None):
    def old_walk_fun_helper(ilist, func=None, count=0):
        tlist = []
        if(isinstance(ilist, list) and ilist):
            for q in ilist:
                tlist += old_walk_fun_helper(q, func, count+1)
        else:
            tlist = func(ilist)
        return [tlist] if(count != 0) else tlist
    if(func != None and hasattr(func, '__call__')):
        return old_walk_fun_helper(ilist, func)
    else:
        return []

def walk_fun(ilist, func=None):
    def walk_fun_helper(ilist, func=None, count=0):
        tlist = []
        if(isinstance(ilist, list) and ilist):
            if(ilist[0] == "Red"): # Only evaluate sub-branches if current level is Red
                for q in ilist:
                    tlist += walk_fun_helper(q, func, count+1)
        else:
            tlist = func(ilist)
        return [tlist] if(count != 0) else tlist
    if(func != None and hasattr(func, '__call__')):
        return walk_fun_helper(ilist, func)
    else:
        return []

# Crude tree structure, first element is always its colour; following elements are its children
tree_list = \
["Red",
    ["Red", 
        ["Red", 
            []
        ], 
        ["White", 
            []
        ],
        ["White", 
            []
        ]
    ],
    ["White",
        ["White", 
            []
        ],
        ["White", 
            []
        ]
    ],
    ["Red", 
        []
    ]
]

red_counter = counter()
eval_counter = counter()
old_walk_fun(tree_list, lambda x: (red_counter.count_up(), eval_counter.count_up()) if(x == "Red") else eval_counter.count_up())
print "Unconditionally walking"
print "Reds found: %d" % red_counter.count
print "Evaluations made: %d" % eval_counter.count
print ""

red_counter = counter()
eval_counter = counter()
walk_fun(tree_list, lambda x: (red_counter.count_up(), eval_counter.count_up()) if(x == "Red") else eval_counter.count_up())
print "Selectively walking"
print "Reds found: %d" % red_counter.count
print "Evaluations made: %d" % eval_counter.count
print ""

答案 2 :(得分:0)

你有多努力快速进行连通性测试?

要测试连通性的图形,我会以随机顺序选择边缘,并在看到连接它们的边缘时使用union-find合并顶点。如果连接了图形,我可以提前终止,并且我有一种连通性证书 - 连接两个先前未连接的顶点集的边缘。

当您在树上工作/按照二分图上的路径时,您将从图中删除边。如果您删除的边缘不在连通性证书中,则图表仍必须连接 - 这看起来像是对我的快速检查。如果它在连通性证书中,您可以在添加边缘之前备份到union / find状态,然后尝试添加新边缘,而不是重复完整的连通性测试。​​

根据您确切定义路径的方式,您可以说该路径的扩展将永远不会包含使用顶点子集的边 - 例如到目前为止在路径内部的顶点。如果源自那些不可触及的顶点的边足以使图连接,那么路径的任何扩展都不能使其不连接。那么至少你只需要计算不同路径的数量。如果原始图是常规的,我希望找到一些动态编程递归,让你在不明确枚举它们的情况下对它们进行计数。