Algoritme de Hierholzer per a gràfics dirigits

Algoritme de Hierholzer per a gràfics dirigits

Donat un gràfic eulerià dirigit, la tasca és imprimir un Circuit d'Euler . Un circuit d'Euler és un camí que travessa cada aresta d'un gràfic exactament una vegada i el camí acaba al vèrtex inicial.

Nota: El gràfic donat conté un circuit d'Euler.

Exemple:



Entrada: Gràfic dirigit

Algoritme de Hierholzer per a gràfics dirigits

Sortida: 0 3 4 0 2 1 0

Requisits previs:

  • Hem comentat el problema d'esbrinar si un graf donat és eulerià o no per a un gràfic no dirigit
  • Condicions per al circuit eulerià en un Grpag dirigit: (1) Tots els vèrtexs pertanyen a un sol component fortament connectat. (2) Tots els vèrtexs tenen el mateix grau d'entrada i grau exterior. Tingueu en compte que per a un gràfic no dirigit la condició és diferent (tots els vèrtexs tenen grau parell)

Enfocament:

  1. Trieu qualsevol vèrtex inicial v i seguiu un rastre d'arestes des d'aquest vèrtex fins a tornar a v. No és possible quedar-se encallat en cap vèrtex que no sigui v perquè el grau i el grau exterior de cada vèrtex han de ser iguals quan el rastre entra en un altre vèrtex w ha d'haver una aresta no utilitzada que surt de w. El recorregut format d'aquesta manera és un recorregut tancat però pot ser que no cobreixi tots els vèrtexs i arestes del gràfic inicial.
  2. Sempre que existeixi un vèrtex u que pertanyi al recorregut actual però que tingui vores adjacents que no formen part del recorregut, inicieu un altre sender des de u seguint vores no utilitzades fins a tornar a u i incorporeu-vos al recorregut format d'aquesta manera amb el recorregut anterior.

Il·lustració:

Prenent un exemple del gràfic anterior amb 5 nodes: adj = {{2 3} {0} {1} {4} {0}}.

  1. Comença al vèrtex 0 :
    • Camí actual: [0]
    • Circuit: []
  2. Vèrtex 0 → 3 :
    • Camí actual: [0 3]
    • Circuit: []
  3. Vèrtex 3 → 4 :
    • Camí actual: [0 3 4]
    • Circuit: []
  4. Vèrtex 4 → 0 :
    • Camí actual: [0 3 4 0]
    • Circuit: []
  5. Vèrtex 0 → 2 :
    • Camí actual: [0 3 4 0 2]
    • Circuit: []
  6. Vèrtex 2 → 1 :
    • Camí actual: [0 3 4 0 2 1]
    • Circuit: []
  7. Vèrtex 1 → 0 :
    • Camí actual: [0 3 4 0 2 1 0]
    • Circuit: []
  8. Tornar enrere al vèrtex 0 : Afegiu 0 al circuit.
    • Camí actual: [0 3 4 0 2 1]
    • Circuit: [0]
  9. Tornar enrere al vèrtex 1 : Afegiu 1 al circuit.
    • Camí actual: [0 3 4 0 2]
    • Circuit: [0 1]
  10. Tornar enrere al vèrtex 2 : Afegiu 2 al circuit.
    • Camí actual: [0 3 4 0]
    • Circuit: [0 1 2]
  11. Tornar enrere al vèrtex 0 : Afegiu 0 al circuit.
    • Camí actual: [0 3 4]
    • Circuit: [0 1 2 0]
  12. Tornar enrere al vèrtex 4 : Afegiu 4 al circuit.
    • Camí actual: [0 3]
    • Circuit: [0 1 2 0 4]
  13. Tornar enrere al vèrtex 3 : Afegiu 3 al circuit.
    • Camí actual: [0]
    • Circuit: [0 1 2 0 4 3]
  14. Tornar enrere al vèrtex 0 : Afegiu 0 al circuit.
    • Camí actual: []
    • Circuit: [0 1 2 0 4 3 0]

A continuació es mostra la implementació de l'enfocament anterior: 

C++
   // C++ program to print Eulerian circuit in given   // directed graph using Hierholzer algorithm   #include          using     namespace     std  ;   // Function to print Eulerian circuit   vector   <  int  >     printCircuit  (  vector   <  vector   <  int  >>     &  adj  )     {      int     n     =     adj  .  size  ();      if     (  n     ==     0  )      return     {};      // Maintain a stack to keep vertices      // We can start from any vertex here we start with 0      vector   <  int  >     currPath  ;      currPath  .  push_back  (  0  );      // list to store final circuit      vector   <  int  >     circuit  ;      while     (  currPath  .  size  ()     >     0  )     {      int     currNode     =     currPath  [  currPath  .  size  ()     -     1  ];      // If there's remaining edge in adjacency list      // of the current vertex      if     (  adj  [  currNode  ].  size  ()     >     0  )     {          // Find and remove the next vertex that is      // adjacent to the current vertex      int     nextNode     =     adj  [  currNode  ].  back  ();      adj  [  currNode  ].  pop_back  ();      // Push the new vertex to the stack      currPath  .  push_back  (  nextNode  );      }      // back-track to find remaining circuit      else     {      // Remove the current vertex and      // put it in the circuit      circuit  .  push_back  (  currPath  .  back  ());      currPath  .  pop_back  ();      }      }      // reverse the result vector       reverse  (  circuit  .  begin  ()     circuit  .  end  ());          return     circuit  ;   }   int     main  ()     {      vector   <  vector   <  int  >>     adj     =     {{  2       3  }     {  0  }     {  1  }     {  4  }     {  0  }};      vector   <  int  >     ans     =     printCircuit  (  adj  );          for     (  auto     v  :     ans  )     cout      < <     v      < <     ' '  ;      cout      < <     endl  ;      return     0  ;   }   
Java
   // Java program to print Eulerian circuit in given   // directed graph using Hierholzer algorithm   import     java.util.*  ;   class   GfG     {      // Function to print Eulerian circuit      static     List   <  Integer  >     printCircuit  (  List   <  List   <  Integer  >>     adj  )     {      int     n     =     adj  .  size  ();      if     (  n     ==     0  )      return     new     ArrayList   <>  ();      // Maintain a stack to keep vertices      // We can start from any vertex here we start with 0      List   <  Integer  >     currPath     =     new     ArrayList   <>  ();      currPath  .  add  (  0  );      // list to store final circuit      List   <  Integer  >     circuit     =     new     ArrayList   <>  ();      while     (  currPath  .  size  ()     >     0  )     {      int     currNode     =     currPath  .  get  (  currPath  .  size  ()     -     1  );      // If there's remaining edge in adjacency list      // of the current vertex      if     (  adj  .  get  (  currNode  ).  size  ()     >     0  )     {      // Find and remove the next vertex that is      // adjacent to the current vertex      int     nextNode     =     adj  .  get  (  currNode  ).  get  (  adj  .  get  (  currNode  ).  size  ()     -     1  );      adj  .  get  (  currNode  ).  remove  (  adj  .  get  (  currNode  ).  size  ()     -     1  );      // Push the new vertex to the stack      currPath  .  add  (  nextNode  );      }      // back-track to find remaining circuit      else     {      // Remove the current vertex and      // put it in the circuit      circuit  .  add  (  currPath  .  get  (  currPath  .  size  ()     -     1  ));      currPath  .  remove  (  currPath  .  size  ()     -     1  );      }      }      // reverse the result vector      Collections  .  reverse  (  circuit  );      return     circuit  ;      }      public     static     void     main  (  String  []     args  )     {      List   <  List   <  Integer  >>     adj     =     new     ArrayList   <>  ();      adj  .  add  (  new     ArrayList   <>  (  Arrays  .  asList  (  2       3  )));      adj  .  add  (  new     ArrayList   <>  (  Arrays  .  asList  (  0  )));         adj  .  add  (  new     ArrayList   <>  (  Arrays  .  asList  (  1  )));         adj  .  add  (  new     ArrayList   <>  (  Arrays  .  asList  (  4  )));         adj  .  add  (  new     ArrayList   <>  (  Arrays  .  asList  (  0  )));         List   <  Integer  >     ans     =     printCircuit  (  adj  );      for     (  int     v     :     ans  )     System  .  out  .  print  (  v     +     ' '  );      System  .  out  .  println  ();      }   }   
Python
   # Python program to print Eulerian circuit in given   # directed graph using Hierholzer algorithm   # Function to print Eulerian circuit   def   printCircuit  (  adj  ):   n   =   len  (  adj  )   if   n   ==   0  :   return   []   # Maintain a stack to keep vertices   # We can start from any vertex here we start with 0   currPath   =   [  0  ]   # list to store final circuit   circuit   =   []   while   len  (  currPath  )   >   0  :   currNode   =   currPath  [  -  1  ]   # If there's remaining edge in adjacency list   # of the current vertex   if   len  (  adj  [  currNode  ])   >   0  :   # Find and remove the next vertex that is   # adjacent to the current vertex   nextNode   =   adj  [  currNode  ]  .  pop  ()   # Push the new vertex to the stack   currPath  .  append  (  nextNode  )   # back-track to find remaining circuit   else  :   # Remove the current vertex and   # put it in the circuit   circuit  .  append  (  currPath  .  pop  ())   # reverse the result vector   circuit  .  reverse  ()   return   circuit   if   __name__   ==   '__main__'  :   adj   =   [[  2     3  ]   [  0  ]   [  1  ]   [  4  ]   [  0  ]]   ans   =   printCircuit  (  adj  )   for   v   in   ans  :   print  (  v     end  =  ' '  )   print  ()   
C#
   // C# program to print Eulerian circuit in given   // directed graph using Hierholzer algorithm   using     System  ;   using     System.Collections.Generic  ;   class     GfG     {          // Function to print Eulerian circuit      static     List   <  int  >     printCircuit  (  List   <  List   <  int  >>     adj  )     {      int     n     =     adj  .  Count  ;      if     (  n     ==     0  )      return     new     List   <  int  >  ();      // Maintain a stack to keep vertices      // We can start from any vertex here we start with 0      List   <  int  >     currPath     =     new     List   <  int  >     {     0     };      // list to store final circuit      List   <  int  >     circuit     =     new     List   <  int  >  ();      while     (  currPath  .  Count     >     0  )     {      int     currNode     =     currPath  [  currPath  .  Count     -     1  ];      // If there's remaining edge in adjacency list      // of the current vertex      if     (  adj  [  currNode  ].  Count     >     0  )     {      // Find and remove the next vertex that is      // adjacent to the current vertex      int     nextNode     =     adj  [  currNode  ][  adj  [  currNode  ].  Count     -     1  ];      adj  [  currNode  ].  RemoveAt  (  adj  [  currNode  ].  Count     -     1  );      // Push the new vertex to the stack      currPath  .  Add  (  nextNode  );      }      // back-track to find remaining circuit      else     {      // Remove the current vertex and      // put it in the circuit      circuit  .  Add  (  currPath  [  currPath  .  Count     -     1  ]);      currPath  .  RemoveAt  (  currPath  .  Count     -     1  );      }      }      // reverse the result vector      circuit  .  Reverse  ();      return     circuit  ;      }      static     void     Main  (  string  []     args  )     {      List   <  List   <  int  >>     adj     =     new     List   <  List   <  int  >>     {      new     List   <  int  >     {     2       3     }      new     List   <  int  >     {     0     }      new     List   <  int  >     {     1     }      new     List   <  int  >     {     4     }      new     List   <  int  >     {     0     }      };      List   <  int  >     ans     =     printCircuit  (  adj  );      foreach     (  int     v     in     ans  )     {      Console  .  Write  (  v     +     ' '  );      }      Console  .  WriteLine  ();      }   }   
JavaScript
   // JavaScript program to print Eulerian circuit in given   // directed graph using Hierholzer algorithm   // Function to print Eulerian circuit   function     printCircuit  (  adj  )     {      let     n     =     adj  .  length  ;      if     (  n     ===     0  )      return     [];      // Maintain a stack to keep vertices      // We can start from any vertex here we start with 0      let     currPath     =     [  0  ];      // list to store final circuit      let     circuit     =     [];      while     (  currPath  .  length     >     0  )     {      let     currNode     =     currPath  [  currPath  .  length     -     1  ];      // If there's remaining edge in adjacency list      // of the current vertex      if     (  adj  [  currNode  ].  length     >     0  )     {      // Find and remove the next vertex that is      // adjacent to the current vertex      let     nextNode     =     adj  [  currNode  ].  pop  ();      // Push the new vertex to the stack      currPath  .  push  (  nextNode  );      }      // back-track to find remaining circuit      else     {      // Remove the current vertex and      // put it in the circuit      circuit  .  push  (  currPath  .  pop  ());      }      }      // reverse the result vector      circuit  .  reverse  ();      return     circuit  ;   }   let     adj     =     [[  2       3  ]     [  0  ]     [  1  ]     [  4  ]     [  0  ]];   let     ans     =     printCircuit  (  adj  );   for     (  let     v     of     ans  )     {      console  .  log  (  v       ' '  );   }   

Sortida
0 3 4 0 2 1 0  

Complexitat temporal:  O(V + E) on V és el nombre de vèrtexs i E és el nombre d'arestes del gràfic. La raó d'això és perquè l'algoritme realitza una cerca en profunditat (DFS) i visita cada vèrtex i cada aresta exactament una vegada. Per tant, per a cada vèrtex triga O(1) temps a visitar-lo i per a cada aresta triga O(1) temps a recórrer-lo.

Complexitat espacial : O(V + E) com a algorisme utilitza una pila per emmagatzemar el camí actual i una llista per emmagatzemar el circuit final. La mida màxima de la pila pot ser V + E en el pitjor, de manera que la complexitat espacial és O (V + E).

Crea un qüestionari

Articles Més Populars

Categoria

Articles D'Interès