我有一个有趣的图论理论问题。我得到一个有三个节点和一组边的树T.当然,T是无向的。每条边都有权重,表示必须访问多少次(至少)。我们使用边缘从一个节点到另一个节点漫步,任务是找到满足上述条件的最少数量的所需步骤。我可以从任何节点开始。
例如,这棵树(括号中的边缘权重):
1 - 2(1)
2 - 3(1)
3 - 4(2)
4 - 5(1)
4 - 6(1)
我们需要8步才能走这棵树。这是例如:1-> 2-> 3-> 4-> 3-> 4-> 5-> 4-> 6
我不知道如何处理这个算法。是否有可能找到这个最佳旅游,或者我们能不能直接找到这个最小数量?
答案 0 :(得分:6)
在图表中添加与每条边的权重相对应的额外边。 (即如果a-> b的权重为3,那么你的图表应包括a和b之间的3个无向边连接。)
然后你想要找到的东西在这张图上被称为欧拉踪迹。
可以关闭欧拉轨迹(如果开始==结束)或打开(如果开始!=结束)。
如果所有节点都具有均匀度,则存在已关闭的路径。
如果除2之外的所有节点都具有均匀度,则存在开放路径。
可以使用Fleury算法找到路径(如果速度太慢,也会存在更快的线性算法)。
如果您的图形不满足欧拉轨迹的要求,则只需添加最小数量的额外边缘,直到它为止。
这样做的一种方法是在树上执行深度优先搜索,并跟踪可以添加到每个子树的最小边数,以便它具有0,1或2个奇度顶点。这应该花费时间线性的树中的节点数。
此Python代码计算图表的最短步骤数。 (要构建图形,您应该将其视为带根图并为远离根的每条边添加边缘)
from collections import defaultdict
D=defaultdict(list)
D[1].append((2,1))
D[2].append((3,1))
D[3].append((4,2))
D[4].append((5,1))
D[4].append((6,1))
BIGNUM=100000
class Memoize:
def __init__(self, fn):
self.fn = fn
self.memo = {}
def __call__(self, *args):
if not self.memo.has_key(args):
self.memo[args] = self.fn(*args)
return self.memo[args]
@Memoize
def min_odd(node,num_odd,odd,k):
"""Return minimum cost for num_odd (<=2) odd vertices in subtree centred at node, and using only children >=k
odd is 1 if we have an odd number of edges into this node from already considered edges."""
edges=D[node]
if k==len(edges):
# No more children to consider, and no choices to make
if odd:
return 0 if num_odd==1 else BIGNUM
return 0 if num_odd==0 else BIGNUM
# We decide whether to add another edge, and how many of the odd vertices to have coming from the subtree
dest,w0 = edges[k]
best = BIGNUM
for extra in [0,1]:
w = w0+extra
for sub_odd in range(num_odd+1):
best = min(best, w + min_odd(dest,sub_odd,w&1,0) + min_odd(node,num_odd-sub_odd,(odd+w)&1,k+1) )
return best
root = 1
print min( min_odd(root,2,0,0),min_odd(root,0,0,0) )