📌  相关文章
📜  使用每条边行进每个节点的路径(柯尼斯堡七桥)

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

使用每条边行进每个节点的路径(柯尼斯堡七桥)

在这些节点之间有 n 个节点和 m 个网桥。使用每条边(如果可能)打印通过每个节点的可能路径,只通过每条边一次。

例子 :

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"

它是图论中著名的问题之一,被称为“哥尼斯堡七桥”问题。这个问题在 1735 年被著名的数学家 Leonhard Euler 解决了。这个问题也被认为是图论的开端。
当时的问题是:有 7 座桥梁连接着普鲁士柯尼斯堡市周围的 4 个土地。有没有什么方法可以从任何一块土地开始,通过每座桥一次且仅一次?请查看这些维基百科图像以获得更清晰的信息。

欧拉首先引入图论来解决这个问题。他将每个土地视为图形的一个节点,并将其间的每座桥视为其间的一条边。现在他计算了该图中是否有任何欧拉路径。如果有一条欧拉路径,那么就有一个解决方案,否则就没有。
这里的问题是 1735 年问题的一般化版本。

下面是实现:

C++
// A C++ program print Eulerian Trail in a
// given Eulerian or Semi-Eulerian Graph
#include 
#include 
#include 
#include 
using namespace std;
 
// A class that represents an undirected graph
class Graph
{
// No. of vertices
    int V;
 
    // A dynamic array of adjacency lists
    list *adj;
public:
 
    // Constructor and destructor
    Graph(int V)
    {
        this->V = V;
        adj = new list[V];
    }
    ~Graph()
    {
        delete [] adj;
    }
 
    // functions to add and remove edge
    void addEdge(int u, int v)
    {
        adj[u].push_back(v);
        adj[v].push_back(u);
    }
 
    void rmvEdge(int u, int v);
 
    // Methods to print Eulerian tour
    void printEulerTour();
    void printEulerUtil(int s);
 
    // This function returns count of vertices
    // reachable from v. It does DFS
    int DFSCount(int v, bool visited[]);
 
    // Utility function to check if edge u-v
    // is a valid next edge in Eulerian trail or circuit
    bool isValidNextEdge(int u, int v);
};
 
/* The main function that print Eulerian Trail.
It first finds an odd degree vertex (if there is any)
and then calls printEulerUtil() to print the path */
void Graph::printEulerTour()
{
    // Find a vertex with odd degree
    int u = 0;
 
    for (int i = 0; i < V; i++)
        if (adj[i].size() & 1)
        {
            u = i;
            break;
        }
 
    // Print tour starting from oddv
    printEulerUtil(u);
    cout << endl;
}
 
// Print Euler tour starting from vertex u
void Graph::printEulerUtil(int u)
{
 
    // Recur for all the vertices adjacent to
    // this vertex
    list::iterator i;
    for (i = adj[u].begin(); i != adj[u].end(); ++i)
    {
        int v = *i;
 
        // If edge u-v is not removed and it's a a
        // valid next edge
        if (v != -1 && isValidNextEdge(u, v))
        {
            cout << u << "-" << v << " ";
            rmvEdge(u, v);
            printEulerUtil(v);
        }
    }
}
 
// The function to check if edge u-v can be considered
// as next edge in Euler Tout
bool Graph::isValidNextEdge(int u, int v)
{
 
    // The edge u-v is valid in one of the following
    // two cases:
 
    // 1) If v is the only adjacent vertex of u
    int count = 0; // To store count of adjacent vertices
    list::iterator i;
    for (i = adj[u].begin(); i != adj[u].end(); ++i)
        if (*i != -1)
            count++;
    if (count == 1)
        return true;
 
 
    // 2) If there are multiple adjacents, then u-v
    //    is not a bridge
    // Do following steps to check if u-v is a bridge
 
    // 2.a) count of vertices reachable from u
    bool visited[V];
    memset(visited, false, V);
    int count1 = DFSCount(u, visited);
 
    // 2.b) Remove edge (u, v) and after removing
    // the edge, count vertices reachable from u
    rmvEdge(u, v);
    memset(visited, false, V);
    int count2 = DFSCount(u, visited);
 
    // 2.c) Add the edge back to the graph
    addEdge(u, v);
 
    // 2.d) If count1 is greater, then edge (u, v)
    // is a bridge
    return (count1 > count2)? false: true;
}
 
// This function removes edge u-v from graph.
// It removes the edge by replacing adjacent
// vertex value with -1.
void Graph::rmvEdge(int u, int v)
{
    // Find v in adjacency list of u and replace
    // it with -1
    list::iterator iv = find(adj[u].begin(),
                                adj[u].end(), v);
    *iv = -1;
 
 
    // Find u in adjacency list of v and replace
    // it with -1
    list::iterator iu = find(adj[v].begin(),
                                  adj[v].end(), u);
    *iu = -1;
}
 
// A DFS based function to count reachable
// vertices from v
int Graph::DFSCount(int v, bool visited[])
{
    // Mark the current node as visited
    visited[v] = true;
    int count = 1;
 
    // Recur for all vertices adjacent to this vertex
    list::iterator i;
    for (i = adj[v].begin(); i != adj[v].end(); ++i)
        if (*i != -1 && !visited[*i])
            count += DFSCount(*i, visited);
 
    return count;
}
 
// Driver program to test above function
int main()
{
    // Let us first create and test
    // graphs shown in above figure
    Graph g1(4);
    g1.addEdge(0, 1);
    g1.addEdge(0, 2);
    g1.addEdge(1, 2);
    g1.addEdge(2, 3);
    g1.printEulerTour();
 
    Graph g3(4);
    g3.addEdge(0, 1);
    g3.addEdge(1, 0);
    g3.addEdge(0, 2);
    g3.addEdge(2, 0);
    g3.addEdge(2, 3);
    g3.addEdge(3, 1);
 
    // comment out this line and you will see that
    // it gives TLE because there is no possible
    // output g3.addEdge(0, 3);
    g3.printEulerTour();
 
    return 0;
}


Java
// A java program print Eulerian Trail in a
// given Eulerian or Semi-Eulerian Graph
import java.util.*;
 
public class GFG{
 
    // A class that represents an undirected graph
    static class Graph
    {
        // No. of vertices
        int V;
 
        // A dynamic array of adjacency lists
        ArrayList> adj;
 
        // Constructor
        Graph(int V)
        {
            this.V = V;
            adj = new ArrayList>();
 
            for(int i=0; i());
            }
        }
 
 
        // functions to add and remove edge
        void addEdge(int u, int v)
        {
            adj.get(u).add(v);
            adj.get(v).add(u);
        }
 
        // This function removes edge u-v from graph.
        // It removes the edge by replacing adjacent
        // vertex value with -1.
        void rmvEdge(int u, int v)
        {
            // Find v in adjacency list of u and replace
            // it with -1
            int iv = find(adj.get(u), v);
            adj.get(u).set(iv, -1);
 
 
            // Find u in adjacency list of v and replace
            // it with -1
            int iu = find(adj.get(v), u);
            adj.get(v).set(iu, -1);
        }
 
        int find(ArrayList al, int v){
 
            for(int i=0; i count2)? false: true;
        }
    }
 
    // Driver program to test above function
    public static void main(String args[])
    {
        // Let us first create and test
        // graphs shown in above figure
        Graph g1 = new Graph(4);
        g1.addEdge(0, 1);
        g1.addEdge(0, 2);
        g1.addEdge(1, 2);
        g1.addEdge(2, 3);
        g1.printEulerTour();
 
        Graph g3 = new Graph(4);
        g3.addEdge(0, 1);
        g3.addEdge(1, 0);
        g3.addEdge(0, 2);
        g3.addEdge(2, 0);
        g3.addEdge(2, 3);
        g3.addEdge(3, 1);
 
        // comment out this line and you will see that
        // it gives TLE because there is no possible
        // output g3.addEdge(0, 3);
        g3.printEulerTour();
    }
}
 
// This code is contributed by adityapande88.


输出:
2-0  0-1  1-2  2-3  
1-0  0-2  2-3  3-1  1-0  0-2