使用每条边行进每个节点的路径(柯尼斯堡七桥)
在这些节点之间有 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