Hamiltonian Path
The Hamiltonian path problem involves finding a path that visits each vertex in a graph exactly once. It models optimization problems like the traveling salesman path.
Java example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| boolean hasHamiltonianPath(int[][] graph) {
int n = graph.length;
int[] path = new int[n];
return hamPath(graph, 0, path, 0);
}
boolean hamPath(int[][] graph, int currPos, int[] path, int count) {
if (count == n-1) return true;
for (int i = 0; i < n; i++) {
if (graph[currPos][i] == 1 && visited(i, path)) {
path[count] = i;
if (hamPath(graph, i, path, count+1)) {
return true;
}
path[count] = -1;
}
}
return false;
}
|
C++ example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| bool hasHamiltonianPath(vector<vector<int>> graph) {
int n = graph.size();
vector<int> path(n, -1);
return hamPath(graph, 0, path, 0);
}
bool hamPath(vector<vector<int>>& graph, int currPos, vector<int>& path, int count) {
if (count == n-1) return true;
for (int i = 0; i < n; i++) {
if (graph[currPos][i] && !visited(path, i)) {
path[count] = i;
if (hamPath(graph, i, path, count+1)) {
return true;
}
path[count] = -1;
}
}
return false;
}
|
Python example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| def has_hamiltonian_path(graph):
n = len(graph)
path = [-1] * n
return ham_path(graph, 0, path, 0)
def ham_path(graph, curr_pos, path, count):
if count == n-1:
return True
for i in range(n):
if graph[curr_pos][i] and not visited(path, i):
path[count] = i
if ham_path(graph, i, path, count+1):
return True
path[count] = -1
return False
|
Finding a Hamiltonian path is NP-Complete. Used for sequencing and route planning problems.
A Hamiltonian path in a graph is a path that visits every vertex exactly once. Unlike an Eulerian path, which focuses on covering all edges, a Hamiltonian path covers all vertices without repetition. This concept is often used in optimization problems like the Traveling Salesman Problem.
Example Code in Java
Here is a simple Java code to find a Hamiltonian path in a graph using backtracking.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
| public class HamiltonianPath {
static boolean isSafe(int v, int[][] graph, int[] path, int pos) {
if (graph[path[pos - 1]][v] == 0)
return false;
for (int i = 0; i < pos; i++)
if (path[i] == v)
return false;
return true;
}
static boolean hamiltonianPathUtil(int[][] graph, int[] path, int pos) {
if (pos == graph.length) {
return true;
}
for (int v = 1; v < graph.length; v++) {
if (isSafe(v, graph, path, pos)) {
path[pos] = v;
if (hamiltonianPathUtil(graph, path, pos + 1))
return true;
path[pos] = -1;
}
}
return false;
}
public static void main(String[] args) {
int[][] graph = {
{0, 1, 0, 1, 0},
{1, 0, 1, 1, 1},
{0, 1, 0, 0, 1},
{1, 1, 0, 0, 1},
{0, 1, 1, 1, 0},
};
int[] path = new int[graph.length];
path[0] = 0;
if (hamiltonianPathUtil(graph, path, 1))
for (int v : path) System.out.print(v + " ");
else
System.out.println("No Hamiltonian Path exists");
}
}
|
Example Code in C++
In C++, the algorithm remains the same. We use backtracking to find the Hamiltonian path.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
| #include <iostream>
#include <vector>
using namespace std;
bool isSafe(int v, vector<vector<int>> &graph, vector<int> &path, int pos) {
if (graph[path[pos - 1]][v] == 0)
return false;
for (int i = 0; i < pos; i++)
if (path[i] == v)
return false;
return true;
}
bool hamiltonianPathUtil(vector<vector<int>> &graph, vector<int> &path, int pos) {
if (pos == graph.size()) {
return true;
}
for (int v = 1; v < graph.size(); v++) {
if (isSafe(v, graph, path, pos)) {
path[pos] = v;
if (hamiltonianPathUtil(graph, path, pos + 1))
return true;
path[pos] = -1;
}
}
return false;
}
int main() {
vector<vector<int>> graph = {
{0, 1, 0, 1, 0},
{1, 0, 1, 1, 1},
{0, 1, 0, 0, 1},
{1, 1, 0, 0, 1},
{0, 1, 1, 1, 0},
};
vector<int> path(graph.size(), -1);
path[0] = 0;
if (hamiltonianPathUtil(graph, path, 1)) {
for (int v : path) cout << v << " ";
} else {
cout << "No Hamiltonian Path exists";
}
return 0;
}
|
Example Code in Python
Python code for the Hamiltonian path is straightforward and similar to Java and C++.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
| def is_safe(v, graph, path, pos):
if graph[path[pos - 1]][v] == 0:
return False
if v in path:
return False
return True
def hamiltonian_path_util(graph, path, pos):
if pos == len(graph):
return True
for v in range(1, len(graph)):
if is_safe(v, graph, path, pos):
path[pos] = v
if hamiltonian_path_util(graph, path, pos + 1):
return True
path[pos] = -1
return False
graph = [
[0, 1, 0, 1, 0],
[1, 0, 1, 1, 1],
[0, 1, 0, 0, 1],
[1, 1, 0, 0, 1],
[0, 1, 1, 1, 0]
]
path = [-1] * len(graph)
path[0] = 0
if hamiltonian_path_util(graph, path, 1):
print(" ".join(map(str, path)))
else:
print("No Hamiltonian Path exists")
|
This shows you how to find a Hamiltonian path using backtracking in Java, C++, and Python.
Hamiltonian Path vs Hamiltonian Cycle
A Hamiltonian Path visits every vertex in a graph exactly once, but it doesn’t need to return to the starting vertex. A Hamiltonian Cycle, on the other hand, is a Hamiltonian Path that is a cycle, meaning it returns to the starting vertex after visiting all other vertices exactly once.
In simpler terms:
- Hamiltonian Path: Visits all vertices once.
- Hamiltonian Cycle: Visits all vertices once and returns to the start.
Finding a Hamiltonian Cycle in a graph is only a small step away from finding a Hamiltonian Path. If a Hamiltonian Path exists and there’s an edge between the last vertex in the path and the starting vertex, you can form a Hamiltonian Cycle.
For example, if you’ve found a Hamiltonian Path 0 -> 1 -> 2 -> 3 -> 4
, and if there’s an edge from vertex 4 back to vertex 0, then you have a Hamiltonian Cycle 0 -> 1 -> 2 -> 3 -> 4 -> 0
.