简体   繁体   English

如何在没有DFS / BFS的情况下枚举哈密顿循环的可能重建?

[英]How to enumerate possible reconstructions of a Hamiltonian cycle without DFS/BFS?

I have a directed Hamiltonian cycle: 我有一个有向哈密顿循环:

[..., a, b, ... , c, d, ..., e, f, ...]

Where b = next(a) , d = next(c) , and f = next(e) . 其中b = next(a)d = next(c)f = next(e)

Say I delete edges (a, b), (c, d), and (e, f). 假设我删除了边(a,b),(c,d)和(e,f)。

Question : How do I generate all possible recombinations of the graph such that it remains a Hamiltonian cycle (keeping in mind that I may have to reverse the ordering in one of the pieces to fix direction)? 问题 :如何生成图形的所有可能重组,使其保持哈密顿循环(请记住,我可能必须反转其中一个部分中的顺序以确定方向)?

What I know 我知道的

I know that the number of new Hamiltonian cycles reachable by removing n-edges is double-factorial(n-1) . 我知道通过去除n边缘可达到的新汉密尔顿循环的数量是double-factorial(n-1) I also know that if I'm removing two consecutive edges, I'll get duplicate solutions (which I'm fine with ... they should be minimal relative to unique cycles and it keeps the resulting code clean). 我也知道,如果我删除两个连续的边,我会得到重复的解决方案(我很好......它们相对于独特的循环应该是最小的并且它保持结果代码干净)。

What I've tried (in rough Pseudocode) 我尝试过的(粗略的伪代码)

One way to think about this is that any of the yielded Hamiltonian cycles must preserve the property that you have to travel along the pieces of the disconnected graph before jumping to a new piece. 考虑这一点的一种方法是,任何屈服的哈密尔顿循环都必须保留在跳转到新的部分之前必须沿着断开的图形的部分行进的属性。

So, for example, thinking about the cycle above (where n = 3 ), there are the following 3 pieces: 因此,例如,考虑上面的循环(其中n = 3 ),有以下3个部分:

[b, ..., c]
[d, ..., e]
[f, ..., a]

So let's say my new solution starts as follows: 那么让我们说我的新解决方案如下:

[..., a, d, ...]

I know that e is the vertex that must come next from my list of terminal vertices. 我知道e是我的终端顶点列表中必须出现的顶点。

So, using that idea, the Python would be something like this: 所以,使用这个想法,Python将是这样的:

from itertools import permutations

def hamiltonian_cycles(l, s=None, r=None):
    if s is None:
        s = [l[0]]
    if r is None:
        r = l[1:]
    if not r:
        yield s
    else:
        for permutation in permutations(r):
            s1 = s[:] + [permutation[0]]
            for cycle in hamiltonian_cycles(l, s1, permutation[1:]):
                yield cycle
            s2 = s[:] + [(permutation[0][1], permutation[0][0])]
            for cycle in hamiltonian_cycles(l, s2, permutation[1:]):
                yield cycle

>>> l = [('f', 'a'), ('b', 'c'), ('d', 'e')]
>>> for cycle in hamiltonian_cycles(l):
...    print(cycle)
[('f', 'a'), ('b', 'c'), ('d', 'e')]
[('f', 'a'), ('b', 'c'), ('e', 'd')]
[('f', 'a'), ('c', 'b'), ('d', 'e')]
[('f', 'a'), ('c', 'b'), ('e', 'd')]
[('f', 'a'), ('d', 'e'), ('b', 'c')]
[('f', 'a'), ('d', 'e'), ('c', 'b')]
[('f', 'a'), ('e', 'd'), ('b', 'c')]
[('f', 'a'), ('e', 'd'), ('c', 'b')]

This seems ugly and stops working past n=3 , though, hence the question. 这看起来很丑陋并且在n=3停止工作,因此问题就在于此。

Why I don't want to use BFS/DFS 为什么我不想使用BFS / DFS

I need a generator that is linear in the number of edges deleted, not in the number of total edges + vertices. 我需要一个在删除的边数上是线性的生成器,而不是总边数+顶点数。

Thanks to this helpful answer here , here's the code that does it. 由于这个有用的答案在这里 ,这里,做它的代码。

from itertools import chain, permutations, product

def new_edge_sets(deleted_edges):

    def edges_to_pieces(l):
        new_list = []
        n = len(l)
        for i in xrange(-1,n-1):
            new_list.append((l[i%n][1], l[(i+1)%n][0]))
        return new_list

    def permute(it):
        return product(*(permutations(i) for i in it))

    def permute2(it):
        return chain.from_iterable(permute(p) for p in permutations(it))

    def pieces_to_edges(p):
        new_list = []
        n = len(p)
        for i in xrange(n):
            new_list.append((p[i%n][1], p[(i+1)%n][0]))
        return new_list

    def permute3(s):
        return (pieces_to_edges(s[:1] + list(p)) for p in permute2(s[1:]))

    return permute3(edges_to_pieces(deleted_edges))

Example: 例:

>>> deleted_edges = [('a', 'b'), ('c', 'd'), ('e', 'f'), ('g', 'h')]
>>> l = list(new_edge_sets(deleted_edges))
>>> len(l)
48
>>> for new_edges in l:
...     print(new_edges)
[('a', 'b'), ('c', 'd'), ('e', 'f'), ('g', 'h')]
[('a', 'b'), ('c', 'd'), ('e', 'g'), ('f', 'h')]
[('a', 'b'), ('c', 'e'), ('d', 'f'), ('g', 'h')]
[('a', 'b'), ('c', 'e'), ('d', 'g'), ('f', 'h')]
[('a', 'c'), ('b', 'd'), ('e', 'f'), ('g', 'h')]
[('a', 'c'), ('b', 'd'), ('e', 'g'), ('f', 'h')]
[('a', 'c'), ('b', 'e'), ('d', 'f'), ('g', 'h')]
[('a', 'c'), ('b', 'e'), ('d', 'g'), ('f', 'h')]
[('a', 'b'), ('c', 'f'), ('g', 'd'), ('e', 'h')]
[('a', 'b'), ('c', 'f'), ('g', 'e'), ('d', 'h')]
[('a', 'b'), ('c', 'g'), ('f', 'd'), ('e', 'h')]
[('a', 'b'), ('c', 'g'), ('f', 'e'), ('d', 'h')]
[('a', 'c'), ('b', 'f'), ('g', 'd'), ('e', 'h')]
[('a', 'c'), ('b', 'f'), ('g', 'e'), ('d', 'h')]
[('a', 'c'), ('b', 'g'), ('f', 'd'), ('e', 'h')]
[('a', 'c'), ('b', 'g'), ('f', 'e'), ('d', 'h')]
[('a', 'd'), ('e', 'b'), ('c', 'f'), ('g', 'h')]
[('a', 'd'), ('e', 'b'), ('c', 'g'), ('f', 'h')]
[('a', 'd'), ('e', 'c'), ('b', 'f'), ('g', 'h')]
[('a', 'd'), ('e', 'c'), ('b', 'g'), ('f', 'h')]
[('a', 'e'), ('d', 'b'), ('c', 'f'), ('g', 'h')]
[('a', 'e'), ('d', 'b'), ('c', 'g'), ('f', 'h')]
[('a', 'e'), ('d', 'c'), ('b', 'f'), ('g', 'h')]
[('a', 'e'), ('d', 'c'), ('b', 'g'), ('f', 'h')]
[('a', 'd'), ('e', 'f'), ('g', 'b'), ('c', 'h')]
[('a', 'd'), ('e', 'f'), ('g', 'c'), ('b', 'h')]
[('a', 'd'), ('e', 'g'), ('f', 'b'), ('c', 'h')]
[('a', 'd'), ('e', 'g'), ('f', 'c'), ('b', 'h')]
[('a', 'e'), ('d', 'f'), ('g', 'b'), ('c', 'h')]
[('a', 'e'), ('d', 'f'), ('g', 'c'), ('b', 'h')]
[('a', 'e'), ('d', 'g'), ('f', 'b'), ('c', 'h')]
[('a', 'e'), ('d', 'g'), ('f', 'c'), ('b', 'h')]
[('a', 'f'), ('g', 'b'), ('c', 'd'), ('e', 'h')]
[('a', 'f'), ('g', 'b'), ('c', 'e'), ('d', 'h')]
[('a', 'f'), ('g', 'c'), ('b', 'd'), ('e', 'h')]
[('a', 'f'), ('g', 'c'), ('b', 'e'), ('d', 'h')]
[('a', 'g'), ('f', 'b'), ('c', 'd'), ('e', 'h')]
[('a', 'g'), ('f', 'b'), ('c', 'e'), ('d', 'h')]
[('a', 'g'), ('f', 'c'), ('b', 'd'), ('e', 'h')]
[('a', 'g'), ('f', 'c'), ('b', 'e'), ('d', 'h')]
[('a', 'f'), ('g', 'd'), ('e', 'b'), ('c', 'h')]
[('a', 'f'), ('g', 'd'), ('e', 'c'), ('b', 'h')]
[('a', 'f'), ('g', 'e'), ('d', 'b'), ('c', 'h')]
[('a', 'f'), ('g', 'e'), ('d', 'c'), ('b', 'h')]
[('a', 'g'), ('f', 'd'), ('e', 'b'), ('c', 'h')]
[('a', 'g'), ('f', 'd'), ('e', 'c'), ('b', 'h')]
[('a', 'g'), ('f', 'e'), ('d', 'b'), ('c', 'h')]
[('a', 'g'), ('f', 'e'), ('d', 'c'), ('b', 'h')]

To generate all the possible hamiltonian cycles. 生成所有可能的哈密顿循环。 give it a try 试试看

MatrixOperations module made for self convinence with matrix operations like printing and stuff.u can try with normal print statement MatrixOperations模块通过矩阵操作(如打印和stuff.u)实现自我控制,可以尝试使用普通的打印语句
 from matrix import MatrixOperations A=[[0,1,0,1,1,0,0],[1,0,1,0,0,0,0],[0,1,0,1,0,0,1],[1,0,1,0,1,0,1],[1,0,0,1,0,1,0],[0,0,0,0,1,0,1],[0,0,1,1,0,1,0]] print("THE ADJACENCY MATRIX\\n");MatrixOperations.PrintMatrix(A) n=len(A) X=[] vis=[0 for i in range(n)] def hamiltonian(vis,A,i): vis[i]=1 if(len(X)==n-1 and A[i][0]==1): print (X) for j in range(0,n): if (vis[j]==0 and A[i][j]==1): X.append(j) #print(X) this print shows the whole tracing process hamiltonian(vis,A,j) if(len(X)>0): del X[-1] vis[i]=0 print("\\nPossible Hamiltonian cycles") hamiltonian(vis,A,0) 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM