根据每条边的权重向图形添加额外的边。(即如果 a->b 的权重为 3,那么您的图形应该包括 a 和 b 之间的 3 个无向边连接)。
那么你试图找到的就是这张图上的欧拉轨迹。
欧拉轨迹可以是封闭的(如果 start==end)或开放的(如果 start!=end)。
如果所有节点的度数相等,则存在闭合路径。
如果除 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) )