logo

Алгоритм Ієргольцера для орієнтованого графа

Для орієнтованого ейлерового графа завдання полягає в тому, щоб надрукувати Схема Ейлера . Схема Ейлера — це шлях, який проходить кожне ребро графа рівно один раз і закінчується на початковій вершині.

Примітка: Даний граф містить схему Ейлера.

приклад:



Вхід: орієнтований граф

Алгоритм Ієргольцера для орієнтованого графа' title=

Вихід: 0 3 4 0 2 1 0

Передумови:

  • Ми обговорили завдання з'ясувати, чи є даний граф ейлеровим чи ні для неорієнтованого графа
  • Умови для ейлерового контуру в орієнтованому групі: (1) Усі вершини належать одній сильно зв’язній компоненті. (2) Усі вершини мають однаковий внутрішній і зовнішній ступінь. Зверніть увагу, що для неорієнтованого графа умова інша (усі вершини мають парний ступінь)

Підхід:

  1. Виберіть будь-яку початкову вершину v і дотримуйтеся сліду ребер від цієї вершини до повернення до v. Неможливо застрягти на будь-якій вершині, окрім v, тому що вхідний і відступний ступінь кожної вершини мають бути однаковими, коли слід входить в іншу вершину w, має залишатися невикористане ребро, виходячи з w. Тур, сформований таким чином, є закритим туром, але може не охоплювати всі вершини та ребра початкового графа.
  2. Поки існує вершина u, яка належить поточному туру, але має суміжні ребра, які не є частиною туру, почніть інший шлях від u, слідуючи невикористаним ребрам до повернення до u, і приєднайте тур, сформований таким чином, до попереднього туру.

Ілюстрація:

На прикладі наведеного вище графіка з 5 вузлами: adj = {{2 3} {0} {1} {4} {0}}.

  1. Почніть з вершини 0 :
    • Поточний шлях: [0]
    • Схема: []
  2. Вершина 0 → 3 :
    • Поточний шлях: [0 3]
    • Схема: []
  3. Вершина 3 → 4 :
    • Поточний шлях: [0 3 4]
    • Схема: []
  4. Вершина 4 → 0 :
    • Поточний шлях: [0 3 4 0]
    • Схема: []
  5. Вершина 0 → 2 :
    • Поточний шлях: [0 3 4 0 2]
    • Схема: []
  6. Вершина 2 → 1 :
    • Поточний шлях: [0 3 4 0 2 1]
    • Схема: []
  7. Вершина 1 → 0 :
    • Поточний шлях: [0 3 4 0 2 1 0]
    • Схема: []
  8. Зворотний шлях до вершини 0 : Додайте 0 до схеми.
    • Поточний шлях: [0 3 4 0 2 1]
    • Схема: [0]
  9. Зворотний шлях до вершини 1 : Додати 1 до схеми.
    • Поточний шлях: [0 3 4 0 2]
    • Схема: [0 1]
  10. Зворотний шлях до вершини 2 : Додайте 2 до схеми.
    • Поточний шлях: [0 3 4 0]
    • Схема: [0 1 2]
  11. Зворотний шлях до вершини 0 : Додайте 0 до схеми.
    • Поточний шлях: [0 3 4]
    • Схема: [0 1 2 0]
  12. Зворотний шлях до вершини 4 : Додайте 4 до схеми.
    • Поточний шлях: [0 3]
    • Схема: [0 1 2 0 4]
  13. Зворотний шлях до вершини 3 : Додайте 3 до схеми.
    • Поточний шлях: [0]
    • Схема: [0 1 2 0 4 3]
  14. Зворотний шлях до вершини 0 : Додайте 0 до схеми.
    • Поточний шлях: []
    • Схема: [0 1 2 0 4 3 0]

Нижче наведено реалізацію вищезазначеного підходу: 

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

Вихід
0 3 4 0 2 1 0 

Часова складність:  O(V + E), де V — кількість вершин, а E — кількість ребер у графі. Причина цього полягає в тому, що алгоритм виконує пошук у глибину (DFS) і відвідує кожну вершину та кожне ребро рівно один раз. Отже, для кожної вершини потрібно O(1) часу, щоб її відвідати, і для кожного ребра потрібно O(1) часу, щоб її обійти.

Складність простору: O(V + E) як алгоритм використовує стек для зберігання поточного шляху та список для зберігання кінцевої схеми. Максимальний розмір стека може становити V + E у гіршому випадку, тому складність простору становить O(V + E).

Створіть вікторину