📜  无向图中的欧拉路径

📅  最后修改于: 2022-05-13 01:57:54.064000             🧑  作者: Mango

无向图中的欧拉路径

给定一个无向图的邻接矩阵表示。查找图中是否有任何欧拉路径。如果没有路径打印“No Solution”。如果有任何路径打印路径。

例子:

Input : [[0, 1, 0, 0, 1],
         [1, 0, 1, 1, 0],
         [0, 1, 0, 1, 0],
         [0, 1, 1, 0, 0],
         [1, 0, 0, 0, 0]]

Output : 5 -> 1 -> 2 -> 4 -> 3 -> 2

Input : [[0, 1, 0, 1, 1],
         [1, 0, 1, 0, 1],
         [0, 1, 0, 1, 1],
         [1, 1, 1, 0, 0],
         [1, 0, 1, 0, 0]]
Output : "No Solution"

这个问题的基本情况是,如果边数为奇数(即奇数度)的顶点数大于 2,则不存在欧拉路径。
如果它有解决方案并且所有节点都有偶数条边,那么我们可以从任何节点开始我们的路径。
如果它有解并且恰好两个顶点有奇数条边,那么我们必须从这两个顶点之一开始我们的路径。
不会有恰好一个顶点有奇数条边的情况,因为总共有偶数条边。

寻找路径的过程:

  1. 首先,取一个空栈和一个空路径。
  2. 如果所有顶点的边数都是偶数,则从其中任何一个开始。如果其中两个顶点的边数为奇数,则从其中一个开始。将变量 current 设置为此起始顶点。
  3. 如果当前顶点至少有一个相邻节点,则首先发现该节点,然后通过回溯发现当前节点。为此,将当前节点添加到堆栈中,删除当前节点和相邻节点之间的边,将当前节点设置为相邻节点。
  4. 如果当前节点没有任何邻居,则将其添加到路径并弹出堆栈将当前设置为弹出顶点。
  5. 重复过程 3 和 4,直到堆栈为空且当前节点没有任何邻居。

无向图中的欧拉路径

在过程路径变量保存欧拉路径之后。

C++
// Efficient C++ program to
// find out Eulerian path
#include 
using namespace std;
  
// Function to find out the path
// It takes the adjacency matrix 
// representation of the graph as input
void findpath(int graph[][5], int n)
{
    vector numofadj;
  
    // Find out number of edges each vertex has
    for (int i = 0; i < n; i++)
        numofadj.push_back(accumulate(graph[i], 
                                      graph[i] + 5, 0));
  
    // Find out how many vertex has odd number edges
    int startpoint = 0, numofodd = 0;
    for (int i = n - 1; i >= 0; i--)
    {
        if (numofadj[i] % 2 == 1)
        {
            numofodd++;
            startpoint = i;
        }
    }
  
    // If number of vertex with odd number of edges
    // is greater than two return "No Solution".
    if (numofodd > 2) 
    {
        cout << "No Solution" << endl;
        return;
    }
  
    // If there is a path find the path
    // Initialize empty stack and path
    // take the starting current as discussed
    stack stack;
    vector path;
    int cur = startpoint;
  
    // Loop will run until there is element in the stack
    // or current edge has some neighbour.
    while (!stack.empty() or 
            accumulate(graph[cur], 
                       graph[cur] + 5, 0) != 0)
    {
        // If current node has not any neighbour
        // add it to path and pop stack
        // set new current to the popped element
        if (accumulate(graph[cur],
                       graph[cur] + 5, 0) == 0)
        {
            path.push_back(cur);
            cur = stack.top();
            stack.pop();
        }
  
        // If the current vertex has at least one
        // neighbour add the current vertex to stack,
        // remove the edge between them and set the
        // current to its neighbour.
        else 
        {
            for (int i = 0; i < n; i++)
            {
                if (graph[cur][i] == 1) 
                {
                    stack.push(cur);
                    graph[cur][i] = 0;
                    graph[i][cur] = 0;
                    cur = i;
                    break;
                }
            }
        }
    }
  
    // print the path
    for (auto ele : path) cout << ele << " -> ";
    cout << cur << endl;
}
  
// Driver Code
int main() 
{
    // Test case 1
    int graph1[][5] = {{0, 1, 0, 0, 1},
                       {1, 0, 1, 1, 0},
                       {0, 1, 0, 1, 0},
                       {0, 1, 1, 0, 0},
                       {1, 0, 0, 0, 0}};
    int n = sizeof(graph1) / sizeof(graph1[0]);
    findpath(graph1, n);
  
    // Test case 2
    int graph2[][5] = {{0, 1, 0, 1, 1},
                       {1, 0, 1, 0, 1},
                       {0, 1, 0, 1, 1},
                       {1, 1, 1, 0, 0},
                       {1, 0, 1, 0, 0}};
    n = sizeof(graph1) / sizeof(graph1[0]);
    findpath(graph2, n);
  
    // Test case 3
    int graph3[][5] = {{0, 1, 0, 0, 1},
                       {1, 0, 1, 1, 1},
                       {0, 1, 0, 1, 0},
                       {0, 1, 1, 0, 1},
                       {1, 1, 0, 1, 0}};
    n = sizeof(graph1) / sizeof(graph1[0]);
    findpath(graph3, n);
}
  
// This code is contributed by
// sanjeev2552


Java
// Efficient Java program to 
// find out Eulerian path 
import java.util.*;
  
class GFG 
{
  
    // Function to find out the path
    // It takes the adjacency matrix
    // representation of the graph as input
    static void findpath(int[][] graph, int n)
    {
        Vector numofadj = new Vector<>();
  
        // Find out number of edges each vertex has
        for (int i = 0; i < n; i++)
            numofadj.add(accumulate(graph[i], 0));
  
        // Find out how many vertex has odd number edges
        int startPoint = 0, numofodd = 0;
        for (int i = n - 1; i >= 0; i--)
        {
            if (numofadj.elementAt(i) % 2 == 1) 
            {
                numofodd++;
                startPoint = i;
            }
        }
  
        // If number of vertex with odd number of edges
        // is greater than two return "No Solution".
        if (numofodd > 2)
        {
            System.out.println("No Solution");
            return;
        }
  
        // If there is a path find the path
        // Initialize empty stack and path
        // take the starting current as discussed
        Stack stack = new Stack<>();
        Vector path = new Vector<>();
        int cur = startPoint;
  
        // Loop will run until there is element in the stack
        // or current edge has some neighbour.
        while (!stack.isEmpty() || accumulate(graph[cur], 0) != 0)
        {
  
            // If current node has not any neighbour
            // add it to path and pop stack
            // set new current to the popped element
            if (accumulate(graph[cur], 0) == 0)
            {
                path.add(cur);
                cur = stack.pop();
  
                // If the current vertex has at least one
                // neighbour add the current vertex to stack,
                // remove the edge between them and set the
                // current to its neighbour.
            } 
            else 
            {
                for (int i = 0; i < n; i++)
                {
                    if (graph[cur][i] == 1) 
                    {
                        stack.add(cur);
                        graph[cur][i] = 0;
                        graph[i][cur] = 0;
                        cur = i;
                        break;
                    }
                }
            }
        }
  
        // print the path
        for (int ele : path)
            System.out.print(ele + " -> ");
        System.out.println(cur);
    }
  
    static int accumulate(int[] arr, int sum)
    {
        for (int i : arr)
            sum += i;
        return sum;
    }
  
    // Driver Code
    public static void main(String[] args)
    {
  
        // Test case 1
        int[][] graph1 = { { 0, 1, 0, 0, 1 },
                        { 1, 0, 1, 1, 0 },
                        { 0, 1, 0, 1, 0 },
                        { 0, 1, 1, 0, 0 },
                        { 1, 0, 0, 0, 0 } };
        int n = graph1.length;
        findpath(graph1, n);
  
        // Test case 2
        int[][] graph2 = { { 0, 1, 0, 1, 1 },
                        { 1, 0, 1, 0, 1 },
                        { 0, 1, 0, 1, 1 },
                        { 1, 1, 1, 0, 0 },
                        { 1, 0, 1, 0, 0 } };
        n = graph2.length;
        findpath(graph2, n);
  
        // Test case 3
        int[][] graph3 = { { 0, 1, 0, 0, 1 },
                        { 1, 0, 1, 1, 1 },
                        { 0, 1, 0, 1, 0 },
                        { 0, 1, 1, 0, 1 },
                        { 1, 1, 0, 1, 0 } };
        n = graph3.length;
        findpath(graph3, n);
    }
}
  
// This code is contributed by
// sanjeev2552


Python3
# Efficient Python3 program to
# find out Eulerian path
  
# Function to find out the path
# It takes the adjacency matrix
# representation of the graph as input
def findpath(graph, n):
      
    numofadj = []
  
    # Find out number of edges each
    # vertex has
    for i in range(n):
        numofadj.append(sum(graph[i]))
  
    # Find out how many vertex has 
    # odd number edges
    startpoint, numofodd = 0, 0
    for i in range(n - 1, -1, -1):
        if (numofadj[i] % 2 == 1):
            numofodd += 1
            startpoint = i
  
    # If number of vertex with odd number of edges
    # is greater than two return "No Solution".
    if (numofodd > 2):
        print("No Solution")
        return
  
    # If there is a path find the path
    # Initialize empty stack and path
    # take the starting current as discussed
    stack = []
    path = []
    cur = startpoint
  
    # Loop will run until there is element in the
    # stack or current edge has some neighbour.
    while (len(stack) > 0 or sum(graph[cur])!= 0):
          
        # If current node has not any neighbour
        # add it to path and pop stack set new 
        # current to the popped element
        if (sum(graph[cur]) == 0):
            path.append(cur)
            cur = stack[-1]
            del stack[-1]
  
        # If the current vertex has at least one
        # neighbour add the current vertex to stack,
        # remove the edge between them and set the
        # current to its neighbour.
        else:
            for i in range(n):
                if (graph[cur][i] == 1):
                    stack.append(cur)
                    graph[cur][i] = 0
                    graph[i][cur] = 0
                    cur = i
                    break
  
    # Print the path
    for ele in path:
        print(ele, end = " -> ")
          
    print(cur)
  
# Driver Code
if __name__ == '__main__':
      
    # Test case 1
    graph1 = [ [ 0, 1, 0, 0, 1 ],
               [ 1, 0, 1, 1, 0 ],
               [ 0, 1, 0, 1, 0 ],
               [ 0, 1, 1, 0, 0 ],
               [ 1, 0, 0, 0, 0 ] ]
    n = len(graph1)
    findpath(graph1, n)
  
    # Test case 2
    graph2 = [ [ 0, 1, 0, 1, 1 ],
               [ 1, 0, 1, 0, 1 ],
               [ 0, 1, 0, 1, 1 ],
               [ 1, 1, 1, 0, 0 ],
               [ 1, 0, 1, 0, 0 ] ]
    n = len(graph2)
    findpath(graph2, n)
  
    # Test case 3
    graph3 = [ [ 0, 1, 0, 0, 1 ],
               [ 1, 0, 1, 1, 1 ],
               [ 0, 1, 0, 1, 0 ],
               [ 0, 1, 1, 0, 1 ],
               [ 1, 1, 0, 1, 0 ] ]
    n = len(graph3)
    findpath(graph3, n)
  
# This code is contributed by mohit kumar 29


C#
// Efficient C# program to 
// find out Eulerian path 
using System;
using System.Collections.Generic;
class GFG{
  
// Function to find out the path
// It takes the adjacency matrix
// representation of the graph 
// as input
static void findpath(int[,] graph, 
                     int n)
{
  List numofadj = 
            new List();
  
  // Find out number of edges 
  // each vertex has
  for (int i = 0; i < n; i++)
    numofadj.Add(accumulate(graph, 
                            i, 0));
  
  // Find out how many vertex has 
  // odd number edges
  int startPoint = 0, numofodd = 0;
  for (int i = n - 1; i >= 0; i--)
  {
    if (numofadj[i] % 2 == 1) 
    {
      numofodd++;
      startPoint = i;
    }
  }
  
  // If number of vertex with odd 
  // number of edges is greater than 
  // two return "No Solution".
  if (numofodd > 2)
  {
    Console.WriteLine("No Solution");
    return;
  }
  
  // If there is a path find the path
  // Initialize empty stack and path
  // take the starting current as 
  // discussed
  Stack stack = new Stack();
  List path = new List();
  int cur = startPoint;
  
  // Loop will run until there is element 
  // in the stack or current edge has some 
  // neighbour.
  while (stack.Count != 0 || 
         accumulate(graph, cur, 0) != 0)
  {
  
    // If current node has not any 
    // neighbour add it to path and 
    // pop stack set new current to 
    // the popped element
    if (accumulate(graph,cur, 0) == 0)
    {
      path.Add(cur);
      cur = stack.Pop();
  
      // If the current vertex has at 
      // least one neighbour add the 
      // current vertex to stack, remove 
      // the edge between them and set the
      // current to its neighbour.
    } 
    else 
    {
      for (int i = 0; i < n; i++)
      {
        if (graph[cur, i] == 1) 
        {
          stack.Push(cur);
          graph[cur, i] = 0;
          graph[i, cur] = 0;
          cur = i;
          break;
        }
      }
    }
  }
  
  // print the path
  foreach (int ele in path)
    Console.Write(ele + " -> ");
  Console.WriteLine(cur);
}
  
static int accumulate(int[,] matrix, 
                      int row, int sum)
{    
  int []arr = GetRow(matrix, 
                     row);
    
 foreach (int i in arr)
   sum += i;
 return sum;
}
    
public static int[] GetRow(int[,] matrix, 
                           int row)
{
  var rowLength = matrix.GetLength(1);
  var rowVector = new int[rowLength];
  
  for (var i = 0; i < rowLength; i++)
    rowVector[i] = matrix[row, i];
  
  return rowVector;
}
    
// Driver Code
public static void Main(String[] args)
{
  // Test case 1
  int[,] graph1 = {{0, 1, 0, 0, 1},
                   {1, 0, 1, 1, 0},
                   {0, 1, 0, 1, 0},
                   {0, 1, 1, 0, 0},
                   {1, 0, 0, 0, 0}};
  int n = graph1.GetLength(0);
  findpath(graph1, n);
  
  // Test case 2
  int[,] graph2 = {{0, 1, 0, 1, 1},
                   {1, 0, 1, 0, 1},
                   {0, 1, 0, 1, 1},
                   {1, 1, 1, 0, 0},
                   {1, 0, 1, 0, 0}};
  n = graph2.GetLength(0);
  findpath(graph2, n);
  
  // Test case 3
  int[,] graph3 = {{0, 1, 0, 0, 1},
                   {1, 0, 1, 1, 1},
                   {0, 1, 0, 1, 0},
                   {0, 1, 1, 0, 1},
                   {1, 1, 0, 1, 0}};
  n = graph3.GetLength(0);
  findpath(graph3, n);
}
}
  
// This code is contributed by Rajput-Ji


输出:

4 -> 0 -> 1 -> 3 -> 2 -> 1
No Solution
4 -> 3 -> 2 -> 1 -> 4 -> 0 -> 1 -> 3

时间复杂度:
该算法的运行时间复杂度为 O(E)。该算法也可用于查找欧拉回路。如果路径的第一个和最后一个顶点相同,那么它将是一个欧拉回路。