【问题标题】:Finding a Eulerian Tour寻找欧拉之旅
【发布时间】:2012-09-16 14:52:10
【问题描述】:

我正在尝试解决 Udacity 上的一个问题,描述如下:

# Find Eulerian Tour
#
# Write a function that takes in a graph
# represented as a list of tuples
# and return a list of nodes that
# you would follow on an Eulerian Tour
#
# For example, if the input graph was
# [(1, 2), (2, 3), (3, 1)]
# A possible Eulerian tour would be [1, 2, 3, 1]

我想出了以下解决方案,虽然不像某些递归算法那样优雅,但在我的测试用例中似乎确实有效。

def find_eulerian_tour(graph):
    tour = []

    start_vertex = graph[0][0]
    tour.append(start_vertex)

    while len(graph) > 0:
        current_vertex = tour[len(tour) - 1]
        for edge in graph:
            if current_vertex in edge:
                if edge[0] == current_vertex:
                    current_vertex = edge[1]
                elif edge[1] == current_vertex:
                    current_vertex = edge[0]
                else:
                    # Edit to account for case no tour is possible
                    return False

                graph.remove(edge)
                tour.append(current_vertex)
                break
    return tour

graph = [(1, 2), (2, 3), (3, 1)]
print find_eulerian_tour(graph)

>> [1, 2, 3, 1]

但是,当我提交这个时,我被评分者拒绝了。我做错了什么?我看不到任何错误。

【问题讨论】:

    标签: python algorithm graph discrete-mathematics


    【解决方案1】:

    这是您的算法失败的有效案例:

    graph = [(1, 2), (2, 3), (3, 1), (3, 4), (4, 3)]
    

    利用print 的强大功能了解graphcurrent_vertex 发生了什么。

    另一个提示:将else 下移,使其属于for,并在for 循环未中断时执行。像现在这样,它永远无法执行。 在修正之后,算法仍然失败,当然。

    当然,算法仍然失败。

    当然,算法仍然失败。

    请不要评论说代码不起作用。它没有。即使下面的代码符合 OP 的想法,该算法仍然失败。关键是要表明 OP 的算法是错误的,而 OP 无法确定。为此,需要正确实现 OP 算法(见下文)。错误算法的正确实现仍然不是正确的解决方案。

    很抱歉,我写了所有这些冗长的解释,让这个答案变得更糟,但是人们继续抱怨代码不起作用(当然,重点是表明它是错误的)。他们也对这个答案投了反对票,可能是因为他们希望能够复制代码作为解决方案。但这不是重点,重点是向 OP 表明他的算法存在错误。

    下面的代码没有找到欧拉之旅。寻找其他地方复制代码以传递您的分配!

    def find_eulerian_tour(graph):
        tour = []
    
        current_vertex = graph[0][0]
        tour.append(current_vertex)
    
        while len(graph) > 0:
            print(graph, current_vertex)
            for edge in graph:
                if current_vertex in edge:
                    if edge[0] == current_vertex:
                        current_vertex = edge[1]
                    else:
                        current_vertex = edge[0]
    
                    graph.remove(edge)
                    tour.append(current_vertex)
                    break
            else:
                # Edit to account for case no tour is possible
                return False
        return tour
    
    graph = [(1, 2), (2, 3), (3, 1), (3, 4), (4, 3)]
    print(find_eulerian_tour(graph))
    

    输出:

    [(1, 2), (2, 3), (3, 1), (3, 4), (4, 3)] 1
    [(2, 3), (3, 1), (3, 4), (4, 3)] 2
    [(3, 1), (3, 4), (4, 3)] 3
    [(3, 4), (4, 3)] 1
    False
    

    【讨论】:

    • 该问题询问算法失败的情况。我的回答回答了这个问题。此外,原始程序中还有一个额外的错误,我更正了这个额外的错误。该算法仍然存在错误,即使它的实现现在是正确的。我举了一个例子来说明这一点。您在此评论中举了另一个例子。我不知道为什么(你没有说你为什么举这个例子)。也许你可以解释你的评论?或者将您的示例发布为另一个答案,但我认为没有必要,真的。
    • 我认为每当用户提出问题时,最好一般回答。不仅在特殊情况下:)
    • @MostafaGhadimi OP 询问他的程序是否有错误。我的回答完全回答了这个问题。它还更进一步,展示了如何修改程序以使其执行 OP 可能首先想要编写的内容(这是错误的)。不知道为什么您的陈述“可能有更好的答案”会导致投反对票。
    【解决方案2】:

    我也在同一堂课,WolframH 的回答对我不起作用。这是我的解决方案(已被评分者接受):

    将所有可能的next node 推入一个堆(search),然后在录制时搜索其中的每一个。

    def next_node(edge, current):
        return edge[0] if current == edge[1] else edge[1]
    
    def remove_edge(raw_list, discard):
        return [item for item in raw_list if item != discard]
    
    def find_eulerian_tour(graph):
        search = [[[], graph[0][0], graph]]
        while search:
            path, node, unexplore = search.pop()
            path += [node]
    
            if not unexplore:
                return path
    
            for edge in unexplore:
                if node in edge:
                    search += [[path, next_node(edge, node), remove_edge(unexplore, edge)]]
    
    if __name__ == '__main__':
        graph = [(1, 2), (2, 3), (3, 1), (3, 4), (4, 3)]
        print find_eulerian_tour(graph)
    

    [1, 3, 4, 3, 2, 1]

    【讨论】:

    • 我的回答表明程序仍然失败。这不是任务的完整解决方案。从互联网上复制甚至没有声称是解决方案的随机代码通常不是传递任务的好方法;-)
    【解决方案3】:

    这是您的算法无法处理的情况:4 个顶点上的完整图。在那里粘贴print tour,你会得到:

    >>> cg4 = [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]
    >>> find_eulerian_tour(cg4)
    [0]
    [0, 1]
    [0, 1, 2]
    [0, 1, 2, 0]
    [0, 1, 2, 0, 3]
    [0, 1, 2, 0, 3, 1]
    [0, 1, 2, 0, 3, 1]
    [0, 1, 2, 0, 3, 1]
    [etc.]
    

    我会让你找到你的方法的问题——你可以很容易地在谷歌上搜索一个完整的实现,所以既然你没有,我假设你想要自己解决它的乐趣。 :^)

    编辑:

    嗯。我承认我认为这只是一开始就错过的失败案例。无论如何,@WolframH 比我更新了一个示例,但您也可以查看 5 个顶点上的完整图表,您的代码给出了

    [0, 1, 2, 0, 3, 1, 4, 0]
    

    并错过了边缘 (2,3)、(2,4) 和 (3,4)。

    【讨论】:

      【解决方案4】:

      使用简单的递归比上述解决方案更容易解决问题。

      def find_eulerian_tour(graph):
          tour=[]
          find_tour(graph[0][0],graph,tour)
          return tour
      def find_tour(u,E,tour): 
        for (a,b) in E:
          if a==u:
              E.remove((a,b))
              find_tour(b,E,tour)
          elif b==u:
              E.remove((a,b))
              find_tour(a,E,tour)
        tour.insert(0,u)
      

      此代码适用于任何输入的元组列表并返回游览列表。 如果有的话,请发送建议和更改。 谢谢 @WolframH:如果图中存在任何循环并且输入元组只是为了使您的代码失败,那么您的代码将不起作用。

      【讨论】:

      • 这会为下图产生不正确的输出:[(2, 6), (4, 2), (5, 4), (6, 5), (6, 8), (7 , 9), (8, 7), (9, 6)]。输出为 0->3->2->1->0
      【解决方案5】:

      我在 Udacity 上同样的课程。在从 Wikipedia 阅读 Hierholzer 算法后,我实现了它。这是算法的链接https://en.wikipedia.org/wiki/Eulerian_path

      下面是我的代码。毫无疑问,它被评分者接受了(在做了一些 Python3 到 Python2 的更改之后)。 :)

      #!/usr/bin/env python3
      # Find Eulerian Tour
      #
      # Write a program that takes in a graph
      # represented as a list of tuples
      # and return a list of nodes that
      # you would follow on an Eulerian Tour
      #
      # For example, if the input graph was
      # [(1, 2), (2, 3), (3, 1)]
      # A possible Eulerian tour would be [1, 2, 3, 1]
      
      def get_a_tour():
          '''This function returns a possible tour in the current graph and removes the edges included in that tour, from the graph.'''
          global graph
      
          nodes_degree = {}       # Creating a {node: degree} dictionary for current graph.
          for edge in graph:
              a, b = edge[0], edge[1]
              nodes_degree[a] = nodes_degree.get(a, 0) + 1
              nodes_degree[b] = nodes_degree.get(b, 0) + 1
      
          tour =[]        # Finding a tour in the current graph.
          loop = enumerate(nodes_degree)
          while True:
              try:
                  l = loop.__next__()
                  index = l[0]
                  node = l[1]
                  degree = nodes_degree[node]
                  try:
                      if (tour[-1], node) in graph or (node, tour[-1]) in graph:
                          tour.append(node)
                          try:
                              graph.remove((tour[-2], tour[-1]))
                              nodes_degree[tour[-1]] -= 1     # Updating degree of nodes in the graph, not required but for the sake of completeness.
                              nodes_degree[tour[-2]] -= 1     # Can also be used to check the correctness of program. In the end all degrees must zero.
                          except ValueError:
                              graph.remove((tour[-1], tour[-2]))
                              nodes_degree[tour[-1]] -= 1
                              nodes_degree[tour[-2]] -= 1
                  except IndexError:
                      tour.append(node)
              except StopIteration:
                  loop = enumerate(nodes_degree)
      
              if len(tour) > 2:
                  if tour[0] == tour[-1]:
                      return tour
      
      def get_eulerian_tour():
          '''This function returns a Eulerian Tour for the input graph.'''
          global graph
          tour = get_a_tour()
      
          if graph:   # If stuck at the beginning, finding additional tour in the graph.
              loop = enumerate(tour[: -1])
              l = loop.__next__()
              i = l[0]
              node = l[1]
              try:
                  while True:
                      if node in list(zip(*graph))[0] or node in list(zip(*graph))[1]:
                          t = get_a_tour()    # Retreivng the additional tour
                          j = t.index(node)
                          tour = tour[ : i] + t[j:-1] + t[ :j+1] + tour[i+1: ]        # Joining the two tours.
                          if not graph:       # Found Eulerian Tour
                              return tour     # Returning the Eulerian Tour
                          loop = enumerate(tour[: -1])        # Still stuck? Looping back to search for another tour.
                      l = loop.__next__()
                      i = l[0]
                      node = l[1]
              except StopIteration:   # Oops! seems like the vertices in the current tour cannot connect to rest of the edges in the graph.
                  print("Your graph doesn't seem to be connected")
                  exit()
          else:       # Found the Eulerian Tour in the very first call. Lucky Enough!
              return tour
      
      # Sample inputs
      # graph = [(1, 2), (1, 3), (2, 3), (2, 4), (2, 6), (3, 4), (3, 5), (4, 5), (4, 6)]
      # graph = [(1, 2), (1, 3), (2, 3)]
      # graph = [(1, 2), (1, 3), (2, 3), (2, 4), (2, 6), (3, 4), (3, 5), (4, 5), (4, 6), (9, 10), (10, 11), (11, 9)]
      # graph = [(1, 2), (1, 3), (2, 3), (2, 4), (2, 6), (3, 4), (3, 5), (4, 5), (4, 6), (2, 7), (7, 8), (8, 2)]
      # graph = [(1, 2), (1, 3), (2, 3), (2, 4), (2, 6), (3, 4), (3, 5), (4, 5), (4, 6), (1, 5), (5, 6), (1, 6)]
      # graph = [(1, 2), (2, 3), (3, 1), (3, 4), (4, 3)]
      # graph = [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]
      # graph = [(2, 6), (4, 2), (5, 4), (6, 5), (6, 8), (7, 9), (8, 7), (9, 6)]
      
      # creating a {node: degree} dictionary
      nodes_degree = {}
      for edge in graph:
          a, b = edge[0], edge[1]
          nodes_degree[a] = nodes_degree.get(a, 0) + 1
          nodes_degree[b] = nodes_degree.get(b, 0) + 1
      
      #checking degree
      degrees = nodes_degree.values() # remember it return a view
      for degree in degrees:
          if degree % 2:
              print("Your graph have one or more nodes with odd degrees. Hence an Eulerian Tour is impossible.")
              exit()
      
      #finding Eulerian Tour
      tour = get_eulerian_tour()
      print(tour)
      

      希望这会有所帮助。

      【讨论】:

        【解决方案6】:

        Here isGregor Ulm 网页中的原始代码,它可以工作。

        def find_eulerian_tour(graph):
        
        def freqencies():
            # save all nodes of edges to my_list
            # e.g. [3,4,5,1,2,2,3,5]
            my_list = [x for (x, y) in graph]
            # get the max num of nodes-->create a list
            # set all to 0
            # for i in range(5) = 0 1 2 3 4
            # so range("5" +1) means
            # len=6, result=[0,0,0,0,0,0]
            # so that the index = the number itself
            result = [0 for i in range(max(my_list) + 1)]
            # nodes in my_list, increment
            # e.g. [0,1,2,2,1,2] 
            # 3appears 2times.
            for i in my_list:
                result[i] += 1
            return result
            # this is Frequencies of each nodes.
        
        def find_node(tour):
            for i in tour:
                if freq[i] != 0:
                    return i
            return -1
        
        def helper(tour, next):
            find_path(tour, next)
            u = find_node(tour)
            while sum(freq) != 0:     
                sub = find_path([], u)
                # get the sub_path
                # add them together
                # when draw to u, turn to sub, and then come back to go on the original tour path
                # [:a], start to a; [a+1:] a+1 to end
                tour = tour[:tour.index(u)] + sub + tour[tour.index(u) + 1:]  
                u = find_node(tour)
            return tour
        
        def find_path(tour, next):
            for (x, y) in graph:
                if x == next:
                    # from "double-graph"
                    # pop out the current one and its respondent one
                    # actually it means we delete this edge
                    current = graph.pop(graph.index((x,y)))
                    graph.pop(graph.index((current[1], current[0])))
                    # now add this "next" node into the tour
                    tour.append(current[0])
                    # decrement in frequency
                    freq[current[0]] -= 1
                    freq[current[1]] -= 1
                    return find_path(tour, current[1])
            # if this "next" node is not connected to any other nodes
            # single one
            tour.append(next)
            return tour             
        
        # in graph, all edges get reversed one and be added to graph
        # can call it "double-graph"  
        # it helps to calculate the frequency in find_path
        # actually we can regard frequency as degrees for each node       
        graph += [(y, x) for (x, y) in graph]
        freq = freqencies()   
        # set graph[0][0] as starting point
        return helper([], graph[0][0])
        
        graph = [(1, 2), (2, 3), (3, 1)]
        print find_eulerian_tour(graph)
        

        【讨论】:

          【解决方案7】:

          虽然代码在无向图上失败,但在有向图上运行得很好。从 Udacity 的角度来看,它仍然不能解决手头的问题,但可以被视为相同的低版本。请不要介意使用不当的 Python,因为我还是该语言的新手。


          在底部添加了两个相当复杂的测试场景。


          initialNode = ''
          nglength = 0
          in_graphLength = 0
          normalizedGraph = list()
          path = []
          node_dict = {}
          mod_flag = ''
            
          def find_eulerian_tour(graph):
              global in_graphLength
              in_graphLength = len(graph)
              graph = normalize_graph(graph,[],-1,len(graph))
              print (path)
              return path
          def normalize_graph(graph,nG,remNode,length):
              counter = 0
              global path
              global initialNode
              global in_graphLength
              global nglength
              global normalizedGraph
              localGraph = list()
              path = []
              pathList = []
              if(remNode != -1):
                  normalizedGraph = nG
              baseNode = 0
              if(len(normalizedGraph) != 0):
                  ini1, ini2 = normalizedGraph[0]
                  initialNode = ini1
                  a1,b1 = normalizedGraph[len(normalizedGraph) - 1]
                  baseNode = b1
                  if(remNode != -2):
                      graph.pop(remNode)
              if(remNode == -1):
                  a,b = graph[0]
                  baseNode = b
                  normalizedGraph.append(graph[0])
                  initialNode = a
                  nglength = 1
                  graph.pop(0)
              i = 0
              if(len(graph) != 0):
                  for n1, n2 in graph:
                      i = i + 1
                      if(n1 == baseNode):
                          localGraph = graph[:]
                          if(isJunction((n1,n2),localGraph, nglength)):
                              graph.pop(i-1)
                              graph.append((n1,n2))
                              normalize_graph(graph, normalizedGraph, -2,in_graphLength)
                              break
                          else:
                              normalizedGraph.append((n1, n2))
                              nglength = nglength + 1
                              normalize_graph(graph, normalizedGraph, i - 1,in_graphLength)
                              break
          
              else:
                  if( counter == 0):
                      counter = counter + 1
                      a0, b0 = normalizedGraph[0]
                      for n1, n2 in normalizedGraph:
                          path.append(n1)
                      path.append(a0)
                      path = path
                      return path
          
          def isJunction((n1,n2), graph, nglength):
              global node_dict
              count = 0
              if(len(graph) > 1):
                  for a1, a2 in graph:
                      if (n1 == a1):
                          count = count + 1
                  if (count > 1):
                      if(str(n1) not in node_dict):
                          key = str(n1)
                          node_dict[key] = count
                      else:
                          return handle_degree(n1)
                      return modification_needed((n1, n2), graph, nglength)
                  else:
                      return False
              else:
                  return False
          
          def handle_degree(n1):
              global node_dict
              key = str(n1)
              if(node_dict.get(key) == 2):
                  return False
          
          def modification_needed((n1,n2),graph, tmplength):
              i = 0
              global mod_flag
              if( n2 == initialNode):
                  return True
              if(len(graph) > 1):
                  for b1, b2 in graph:
                      if(n2 == b1):
                          i = i + 1
                          tmplength = tmplength + 1
                          if (b1,b2) in normalizedGraph:
                              mod_flag = True
                              continue
                          if(tmplength < in_graphLength and b2 == initialNode):
                              mod_flag = True
                              continue
                          else:
                              graph.pop(i-1)
                              modification_needed((b1,b2),graph,tmplength)
              return mod_flag
          
          
          #find_eulerian_tour([(1,2),(2,6),(7,2),(6,1),(2,3),(3,5),(3,4),(4,5),(5,7),(7,3),(5,6),(6,7)])
          #find_eulerian_tour([(0,4),(1,0),(4,2),(4,8),(2,5),(9,5),(8,9),(5,4),(5,1),(7,1),(3,7),(1,6),(6,3)])
          

          【讨论】:

            【解决方案8】:

            此解决方案针对 O(V+E) 复杂性进行了优化,即图中边和顶点的数量呈线性

            对于那些直接希望看到代码的人:https://github.com/cubohan/py-algos/blob/master/eulerian_tour.py

            请注意,代码主要违反可读性和 DRY 设计,但在阅读说明后,您可以轻松制作自己的版本。

            # eulerian_tour.py by cubohan
            # circa 2017
            #
            # Problem statement: Given a list of edges, output a list of vertices followed in an eulerian tour
            #
            # complexity analysis: O(E + V) LINEAR
            
            
            def find_eulerian_tour(graph):
                edges = graph
                graph = {}
                degree = {}
                start = edges[0][0]
                count_e = 0
                for e in edges:
                    if not e[0] in graph:
                        graph[e[0]] = {}
                    if not e[0] in degree:
                        degree[e[0]] = 0
                    if not e[1] in graph:
                        graph[e[1]] = {}
                    if not e[1] in degree:
                        degree[e[1]] = 0
                    graph[e[0]][e[1]] = 1
                    graph[e[1]][e[0]] = 1
                    degree[e[0]] += 1
                    degree[e[1]] += 1
                    count_e += 1
                max_d = 0
                this_ = 0
                for v, d in degree.items():
                    if not d%2 == 0:
                        # Eulerian tour not possible as odd degree found!
                        return False 
                    if d>max_d:
                        this_ = v
                        max_d = d
                visited_e = {}
                def is_visited(i, j):
                    key = str(sorted([i,j]))
                    if key in visited_e:
                        return True
                    else:
                        visited_e[key] = True
                        return False
                start = this_
                route = [start]
                indexof = {}
                indexof[start] = 0
                while count_e>0:
                    flag = False
                    for to_v in graph[this_]:
                        if not is_visited(to_v, this_):
                            route.append([to_v])
                            indexof[to_v] = len(route)-1
                            degree[to_v] -= 1
                            if degree[to_v] == 0:
                                del degree[to_v]
                            degree[this_] -= 1
                            if degree[this_] == 0:
                                del degree[this_]
                            this_ = to_v
                            flag = True
                            count_e -= 1
                            break
                    if not flag:
                        break
                for key, v in degree.items():
                    if v <=0:
                        continue
                    try:
                        ind = indexof[key]
                    except Exception as e:
                        continue
                    this_ = key
                    while count_e>0:
                        flag = False
                        for to_v in graph[this_]:
                            if not is_visited(to_v, this_):
                                route[ind].append(to_v)
                                degree[to_v] -= 1
                                degree[this_] -= 1
                                this_ = to_v
                                flag = True
                                count_e -= 1
                                break
                        if not flag:
                            break
                route_ref = []
                for r in route:
                    if type(r) == list:
                        for _r in r:
                            route_ref.append(_r)
                    else:
                        route_ref.append(r)
                return route_ref
            
            if __name__ == "__main__":
                print find_eulerian_tour([(0, 1), (1, 5), (1, 7), (4, 5),(4, 8), (1, 6), (3, 7), (5, 9),(2, 4), (0, 4), (2, 5), (3, 6), (8, 9)])
            

            **首先问题可以分为这些子任务:**

            1. 将图形构建成比边列表更友好的结构,以便于处理,即(邻接列表)

            2. 找到每个顶点的度数以首先检查是否可以进行欧拉之旅(是否只有偶数度数?另外,将这些值存储在以顶点为键的字典中 => 以供以后使用)

            3. 构建欧拉之旅

            我的解决方案背后的概念很简单。

            1. 选择度数最高的顶点作为起点,设置为当前顶点。 (注意:您在计算每个顶点的度数时同时完成此操作。您将所有这些度数存储在字典中。)

            2. 您在路由列表中插入当前顶点,这就是您的答案(注意:还要在路由列表中创建一个顶点字典及其索引。这将在以后使用。)

            3. 如果尚未访问当前顶点的第一条边,则访问它。 (注意:维护了一个已访问边的字典,该字典的键是构成边的一对顶点的排序元组。访问一条边后,通过将其插入字典来标记它已访问。)

            4. 您维护当前顶点和访问顶点的剩余度数(这将在以后证明很有用)(注意:您只需在每次选择之前从生成的度数中减去 1边缘)

            5. 您将当前顶点切换到您决定访问的边的另一端的顶点。

            6. 重复步骤 2-5,直到在当前顶点中找不到未访问的边。 (注意:这意味着你已经回到了你的起始顶点)

            现在考虑这一点:请注意,任何未访问的边/顶点都将构成主图中的子图,它们具有与主图相同的属性,即欧拉之旅可能从子图中的任何顶点开始和结束于相同顶点。

            所有未访问的边都可以通过在这些子图中进行欧拉之旅来访问您只需将这些子之旅与第一个之旅合并。

            下一步:

            1. 当且仅当此顶点的缩减度不为零时,您循环遍历图形的所有顶点并在与主游览列出的相同过程中构建子游览

            2. 这些游览将与之前计算的路线列表合并的方式是,您将考虑从路线列表中开始子游览的顶点的位置替换为子游览输出列表,然后将该路线展平列表

            我们还没有完成!上面有什么问题?

            当您得到一个尚未访问过且不在路线列表中的非零度顶点时会发生什么?!

            警告: 这是一个例外情况。

            您可能会遇到以前未访问过的顶点,因此它们不会出现在主路由列表中。

            循环时忽略这些!您已经访问过的具有非零缩减度的顶点之一是保证在您将从这些顶点开始创建的子游览中引导这些顶点。

            这怎么可能??!!

            从代码链接中给出的测试用例中画一个图,你就会明白了。追踪您的算法在流程的每一步都在做什么。画出来!图像的理解复杂度为 log(N),单词的复杂度为 O(n2)。

            啊,请注意,只有当输入列表中的所有边形成一个图而不是两个独立的不相交图时,此保证才成立。

            【讨论】:

              【解决方案9】:

              您可以模仿 BFS 算法的行为并搭载它。

              注意:我没有尝试使用链表编写答案,因为链表需要定义 2 个类(一个定义节点及其行为,一个定义整个链表及其行为)。但是,为了提高(追加)​​和(删除)行为的效率,您应该使用链表而不是数组:

              def find_eulerian_tour(graph):
                  nodes = set()
              
                  for i in graph:
                      if not i[0] in nodes:
                          nodes.add(i[0])
                      if not i[1] in nodes:
                          nodes.add(i[1])
              
                  tour = []
                  tempstack = []
                  graphtemp = []
              
                  current_vertex = graph[0][0]
                  tour.append(current_vertex)
                  tempstack.append(current_vertex)
                  last_edge = ()
                  count = 0
              
                  while len(set(tempstack)) + 1 < len(nodes) or (count == 0 or tour[0] != tour[len(tour) - 1]):
                      count += 1
                      flag = False
                      for edge in graph:
                         if current_vertex in edge and edge != last_edge:
                              if current_vertex == edge[0]:
                                  current_vertex = edge[1]
                              else:
                                  current_vertex = edge[0]
                              last_edge = edge
                              graphtemp.append(edge)
                              graph.remove(edge)
                              tour.append(current_vertex)
                              tempstack.append(current_vertex)
                              flag = True
                              break
              
                      if flag == False:
                          tour.remove(current_vertex)
                          current_vertex = tempstack[0]
                          tempstack.remove(tempstack[0])
                          graph.append(graphtemp[0])
                          graphtemp.remove(graphtemp[0])
              
              
                  return tour
              
              
              print find_eulerian_tour([(1,2), (2,3), (3,1)])
              print(find_eulerian_tour([(0, 1), (1, 5), (1, 7), (4, 5), (4, 8), (1, 6), (3, 7), (5, 9), (2, 4), (0, 4), (2, 5), (3, 6), (8, 9)]))
              print(find_eulerian_tour([(1, 13), (1, 6), (6, 11), (3, 13), (8, 13), (0, 6), (8, 9),(5, 9), (2, 6), (6, 10), (7, 9), (1, 12), (4, 12), (5, 14), (0, 1),  (2, 3), (4, 11), (6, 9), (7, 14),  (10, 13)]))
              print(find_eulerian_tour([(8, 16), (8, 18), (16, 17), (18, 19), (3, 17), (13, 17), (5, 13),(3, 4), (0, 18), (3, 14), (11, 14), (1, 8), (1, 9), (4, 12), (2, 19),(1, 10), (7, 9), (13, 15), (6, 12), (0, 1), (2, 11), (3, 18), (5, 6), (7, 15), (8, 13), (10, 17)]))
              

              【讨论】:

                【解决方案10】:

                如果我们这样做呢? (刚刚检查过,它通过了 udacity 测试!!)

                import itertools
                def create_tour(alist):
                    return list(itertools.permutations(alist,2))
                

                【讨论】:

                • 虽然目标是学习算法,而不仅仅是重用现有的算法。但它确实让辛苦的工作变得轻松......为努力创造这个功能的人们和平!!!!
                • 不正确:此图和许多其他图失败 [(0, 1), (1, 2), (2, 0), (0, 3), (3, 4), ( 4, 0), (0, 5), (5, 6), (6, 0), (0, 7), (7, 8), (8, 0), (0, 9), (9, 10), (10, 0), (0, 11), (11, 12), (12, 0), (0, 13), (13, 14), (14, 0)]
                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2018-10-21
                • 1970-01-01
                • 2017-08-27
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多