Algoritmo di Hierholzer per grafi diretti

Algoritmo di Hierholzer per grafi diretti

Dato un grafo Euleriano orientato il compito è stampare un Circuito di Eulero . Un circuito di Eulero è un percorso che attraversa ogni bordo di un grafico esattamente una volta e termina sul vertice iniziale.

Nota: Il grafico dato contiene un circuito di Eulero.

Esempio:



Input: grafico diretto

Algoritmo di Hierholzer per grafi diretti

Produzione: 0 3 4 0 2 1 0

Prerequisiti:

  • Abbiamo discusso di problema di scoprire se un dato grafo è euleriano oppure no per un grafico non orientato
  • Condizioni per un circuito Euleriano in un Grpag Diretto: (1) Tutti i vertici appartengono ad un'unica componente fortemente connessa. (2) Tutti i vertici hanno lo stesso grado di entrata e di uscita. Si noti che per un grafo non orientato la condizione è diversa (tutti i vertici hanno grado pari)

Approccio:

  1. Scegli qualsiasi vertice iniziale v e segui una scia di spigoli da quel vertice fino a tornare a v. Non è possibile rimanere bloccati in qualsiasi vertice diverso da v perché il grado inverso e quello esterno di ogni vertice devono essere uguali quando la traccia entra in un altro vertice w deve esserci un bordo inutilizzato che esce da w. Il tour così formato è un tour chiuso ma potrebbe non coprire tutti i vertici e gli spigoli del grafo iniziale.
  2. Finché esiste un vertice u che appartiene al giro attuale ma che ha bordi adiacenti non facenti parte del giro iniziare un altro percorso da u seguendo i bordi inutilizzati fino a ritornare a u e unire il giro così formato al giro precedente.

Illustrazione:

Prendendo l'esempio del grafico sopra con 5 nodi: adj = {{2 3} {0} {1} {4} {0}}.

  1. Inizia dal vertice 0 :
    • Percorso corrente: [0]
    • Circuito: []
  2. Vertice 0 → 3 :
    • Percorso corrente: [0 3]
    • Circuito: []
  3. Vertice 3 → 4 :
    • Percorso corrente: [0 3 4]
    • Circuito: []
  4. Vertice 4 → 0 :
    • Percorso corrente: [0 3 4 0]
    • Circuito: []
  5. Vertice 0 → 2 :
    • Percorso corrente: [0 3 4 0 2]
    • Circuito: []
  6. Vertice 2 → 1 :
    • Percorso corrente: [0 3 4 0 2 1]
    • Circuito: []
  7. Vertice 1 → 0 :
    • Percorso corrente: [0 3 4 0 2 1 0]
    • Circuito: []
  8. Ritorno al vertice 0 : aggiunge 0 al circuito.
    • Percorso corrente: [0 3 4 0 2 1]
    • Circuito: [0]
  9. Ritorno al vertice 1 : Aggiungere 1 al circuito.
    • Percorso corrente: [0 3 4 0 2]
    • Circuito: [0 1]
  10. Ritorno al vertice 2 : Aggiungere 2 al circuito.
    • Percorso corrente: [0 3 4 0]
    • Circuito: [0 1 2]
  11. Ritorno al vertice 0 : aggiunge 0 al circuito.
    • Percorso corrente: [0 3 4]
    • Circuito: [0 1 2 0]
  12. Ritorno al vertice 4 : Aggiungere 4 al circuito.
    • Percorso corrente: [0 3]
    • Circuito: [0 1 2 0 4]
  13. Ritorno al vertice 3 : Aggiungere 3 al circuito.
    • Percorso corrente: [0]
    • Circuito: [0 1 2 0 4 3]
  14. Ritorno al vertice 0 : aggiunge 0 al circuito.
    • Percorso corrente: []
    • Circuito: [0 1 2 0 4 3 0]

Di seguito è riportata l'implementazione dell'approccio di cui sopra: 

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       ' '  );   }   

Produzione
0 3 4 0 2 1 0  

Complessità temporale:  O(V + E) dove V è il numero di vertici ed E è il numero di archi nel grafico. La ragione di ciò è che l'algoritmo esegue una ricerca in profondità (DFS) e visita ciascun vertice e ciascun bordo esattamente una volta. Quindi per ogni vertice occorre O(1) tempo per visitarlo e per ogni spigolo occorre O(1) tempo per attraversarlo.

Complessità dello spazio: O(V + E) poiché l'algoritmo utilizza uno stack per memorizzare il percorso corrente e una lista per memorizzare il circuito finale. La dimensione massima dello stack può essere nel peggiore dei casi V + E, quindi la complessità dello spazio è O (V + E).

Crea quiz

Articoli Più

Categoria

Articoli Interessanti