如果你的结构为:
,我有一棵树或有向无环图
其中r是根节点,p是父节点,c是子节点,b是假设分支。根节点不直接链接到父节点,它只是一个引用。
我在限制条件下找到分支的所有组合:
在此示例中,在约束条件下只能使用两种有效组合:
combo[0] = [b[0], b[1], b[2], b[3]]
combo[1] = [b[0], b[1], b[2], b[4]]
数据结构如b是一个分支对象列表,它具有属性r,c和p,例如:
b[3].r = 1
b[3].p = 3
b[3].c = 2
答案 0 :(得分:3)
这个问题可以在Python中轻松优雅地解决,因为有一个名为“itertools”的模块。
假设我们有HypotheticalBranch类型的对象,它们具有属性r,p和c。就像你在帖子中描述的那样:
class HypotheticalBranch(object):
def __init__(self, r, p, c):
self.r=r
self.p=p
self.c=c
def __repr__(self):
return "HypotheticalBranch(%d,%d,%d)" % (self.r,self.p,self.c)
因此,您的假设分支就是
b=[ HypotheticalBranch(0,0,0),
HypotheticalBranch(0,1,1),
HypotheticalBranch(1,2,1),
HypotheticalBranch(1,3,2),
HypotheticalBranch(1,4,2) ]
返回所有可能的分支组合列表的神奇函数可以这样编写:
import collections, itertools
def get_combos(branches):
rc=collections.defaultdict(list)
for b in branches:
rc[b.r,b.c].append(b)
return itertools.product(*rc.values())
确切地说,此函数返回一个迭代器。通过迭代获取列表。这四行代码将打印出所有可能的组合:
for combo in get_combos(b):
print "Combo:"
for branch in combo:
print " %r" % (branch,)
该程序的输出是:
Combo:
HypotheticalBranch(0,1,1)
HypotheticalBranch(1,3,2)
HypotheticalBranch(0,0,0)
HypotheticalBranch(1,2,1)
Combo:
HypotheticalBranch(0,1,1)
HypotheticalBranch(1,4,2)
HypotheticalBranch(0,0,0)
HypotheticalBranch(1,2,1)
......这正是你想要的。
那么脚本的作用是什么?它为每个组合(根节点,子节点)创建所有假设分支的列表。然后它产生这些列表的乘积,即每个列表中一个项目的所有可能组合。
我希望我能得到你真正想要的东西。
答案 1 :(得分:1)
您的第二个约束意味着您需要最大组合,即所有长度等于最大组合的组合。
我首先遍历“b”结构并创建一个名为“c”的结构来存储所有分支,以存储到每个子节点的所有分支,并由到达它的根节点进行分类。
然后构造输出组合,对于每个子项,您可以包含每个非空的根集中的一个条目。算法的顺序(执行时间)将是输出的顺序,这是您可以获得的最佳顺序。
例如,您的“c”结构将如下所示:
c[i][j] = [b_k0, ...]
--> means c_i has b_k0, ... as branches that connect to root r_j)
对于您提供的示例:
c[0][0] = [0]
c[0][1] = []
c[1][0] = [1]
c[1][1] = [2]
c[2][0] = []
c[2][1] = [3, 4]
使用这种方法对它进行编码应该相当容易。您只需要遍历所有分支“b”并填充“c”的数据结构。然后写一个小的递归函数,遍历“c”中的所有项目。
这是代码(为了测试,我在顶部输入了样本数据):
class Branch:
def __init__(self, r, p, c):
self.r = r
self.p = p
self.c = c
b = [
Branch(0, 0, 0),
Branch(0, 1, 1),
Branch(1, 2, 1),
Branch(1, 3, 2),
Branch(1, 4, 2)
]
total_b = 5 # Number of branches
total_c = 3 # Number of child nodes
total_r = 2 # Number of roots
c = []
for i in range(total_c):
c.append([])
for j in range(total_r):
c[i].append([])
for k in range(total_b):
c[b[k].c][b[k].r].append(k)
combos = []
def list_combos(n_c, n_r, curr):
if n_c == total_c:
combos.append(curr)
elif n_r == total_r:
list_combos(n_c+1, 0, curr)
elif c[n_c][n_r]:
for k in c[n_c][n_r]:
list_combos(n_c, n_r+1, curr + [b[k]])
else:
list_combos(n_c, n_r+1, curr)
list_combos(0, 0, [])
print combos
答案 2 :(得分:1)
这里确实存在两个问题:首先,您需要制定用于解决此问题的算法;其次,您需要实现它(在Python中)。
我假设你想要一个 maximal 分支集合;也就是说,一旦你不能再添加任何分支。如果不这样做,则可以考虑最大集合的所有子集。
因此,对于子节点,我们希望尽可能多地使用分支,但要遵守没有两个父节点共享根的约束。换句话说,来自每个孩子的每个根节点附近最多可能有一个边缘。这似乎表明你想首先在子节点上迭代,然后在根节点的(邻域)上迭代,最后在这些之间的边缘上迭代。这个概念给出了以下伪代码:
for each child node:
for each root node:
remember each permissible edge
find all combinations of permissible edges
>>> import networkx as nx
>>> import itertools
>>>
>>> G = nx.DiGraph()
>>> G.add_nodes_from(["r0", "r1", "p0", "p1", "p2", "p3", "p4", "c0", "c1", "c2"])
>>> G.add_edges_from([("r0", "p0"), ("r0", "p1"), ("r1", "p2"), ("r1", "p3"),
... ("r1", "p4"), ("p0", "c0"), ("p1", "c1"), ("p2", "c1"),
... ("p3", "c2"), ("p4", "c2")])
>>>
>>> combs = set()
>>> leaves = [node for node in G if not G.out_degree(node)]
>>> roots = [node for node in G if not G.in_degree(node)]
>>> for leaf in leaves:
... for root in roots:
... possibilities = tuple(edge for edge in G.in_edges_iter(leaf)
... if G.has_edge(root, edge[0]))
... if possibilities: combs.add(possibilities)
...
>>> combs
set([(('p1', 'c1'),),
(('p2', 'c1'),),
(('p3', 'c2'), ('p4', 'c2')),
(('p0', 'c0'),)])
>>> print list(itertools.product(*combs))
[(('p1', 'c1'), ('p2', 'c1'), ('p3', 'c2'), ('p0', 'c0')),
(('p1', 'c1'), ('p2', 'c1'), ('p4', 'c2'), ('p0', 'c0'))]
上述似乎有效,但我还没有测试过。
答案 3 :(得分:0)
对于每个孩子c,假设父母p(c),根r(p(c)),从p(c)中为r(p(c))中的每个根r选择恰好一个父p(如r是p)的根,并且在组合中包括b,其中b将p连接到c(假设只有一个这样的b,意味着它不是多图)。组合的数量将是每个孩子假设连接到每个根的父母数量的乘积。换句话说,该组合的大小将等于所有子根对的假设连接的乘积。在你的例子中,所有这样的子根对只有一个路径,除了r1-c2,它有两个路径,因此组合集的大小是两个。
这满足了无组合作为另一个子集的约束,因为通过为每个子节点的每个根选择恰好一个父节点,我们最大化连接数。随后添加任何边缘b将导致其根连接到其子节点两次,这是不允许的。由于我们只选择一个,所有组合的长度都完全相同。
递归地实现此选择将产生所需的组合。