我有一棵树,如下所示。
Red
检查。
Red
比所有祖先还Red
(并且不应再次检查)。Not Red
比所有后代都Not Red
。d
。n
。请注意,子节点的值大于父节点。
因此,儿童可以被构建为:
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 = []
这是一个示例树:
我正在尝试计算Red
个节点的数量。树的深度和宽度都很大。所以我想做一种Depth-First-Search并另外使用上面的属性1和2.
如何设计算法来遍历该树?
PS:我标记了这个[python],但算法的任何轮廓都可以。
R
和C
,其大小为r
和c
。 (注意,树的宽度是n=r*c
)。 x, y = divmod(value, c)
。 属性检查的两个规则来自图的连通性: - 如果图形连接边缘[a,b,c]已移除,则它也必须与[a,b]移除(规则1)连接。 - 如果图形断开,边缘[a,b,c]被移除,那么它也必须断开连接边缘d去除[a,b,c,d](规则2)。
所以我真正想做的是检查从[0..n]中挑选d个元素的所有组合。树结构有点帮助,但即使我得到了一个最优的树遍历算法,我仍然会检查太多的组合。 (我刚才注意到了。)
让我解释一下。假设我需要检查[4,5](所以4和5从二分图中删除,如上所述,但这里不相关。)。如果这是“红色”,我的树将阻止我仅检查[4]。那很好。但是,我也应该检查[5]。
如何更改树的结构(可能是图表?)以进一步减少检查次数?
答案 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状态,然后尝试添加新边缘,而不是重复完整的连通性测试。
根据您确切定义路径的方式,您可以说该路径的扩展将永远不会包含使用顶点子集的边 - 例如到目前为止在路径内部的顶点。如果源自那些不可触及的顶点的边足以使图连接,那么路径的任何扩展都不能使其不连接。那么至少你只需要计算不同路径的数量。如果原始图是常规的,我希望找到一些动态编程递归,让你在不明确枚举它们的情况下对它们进行计数。