Python 实现匈牙利算法
def hungary(edges):
result = set()
lenA = max(edge[0] for edge in edges) + 1
lenB = max(edge[1] for edge in edges) + 1
def allVectorsGen():
for x in xrange(lenA):
yield x, None
for x in xrange(lenB):
yield None, x
usedVectors = set()
def getPath(inResult, startVector, path=()), pathUsedVectors=None):
pathUsedVectors = pathUsedVectors or set()
# No need to enumerate edge already in path.
for edge in edges - set(path):
if (edge in result) != inResult:
continue
vectors = set(((edge[0], None), (None, edge[1])))
if not startVector in vectors:
continue
vectors.remove(startVector)
endVector = vectors.pop()
if endVector in pathUsedVectors:
continue
pathUsedVectors.add(endVector)
path = path + (edge,)
# Invert inResult, know & don't know of a & b
subPath = getPath(not inResult, endVector, path, pathUsedVectors)
if not subPath is None:
return subPath
elif len(path) % 2 == 1 and not endVector in usedVectors:
return path
return None
while len(result) < min(lenA, lenB):
for vector in allVectorsGen():
if vector in usedVectors:
continue
path = getPath(False, vector)
if not path is None:
result ^= set(path)
# Every path found, both start vector & end vector will be
# removed from free vectors.
usedVectors.add(vector) # Start vector
usedVectors.add(((path[-1][0] if vector[0] is None else None),
(path[-1][1] if vector[1] is None else None)))
# End vector
break
else:
break
return result
if __name__ == '__main__':
print hungary(set([(0, 1), (0, 4),
(1, 1), (1, 2), (1, 3),
(2, 0), (2, 4),
(3, 0), (3, 1), (3, 4),
(4, 1)]))
坑:
- 生成器表达式生成的生成器只能调用一次。
- set构造器不支持*arg的构造方式。
- 直到Python 2.7.3,还没有frozendict,可以使用frozenset代替。后来我没用。所以dict不能哈希,也就是不能直接入set,可以用frozenset(dictA.iteritems())代替。
- dict转序列的时候只保留键,序列转dict必须每个项的长度为2,所以强转这事儿在dict和序列之间不可逆。
- **传参数必须是dict,不提供自动转换成dict的功能。
- 默认参数传可变对象的时候会造成静态问题,简单的解决方案是传
p=None
然后p = p || set()
- 在没有歧义的情况下可以使用()来声明一个空元组,真萌。