This repository has been archived by the owner on Dec 13, 2024. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy path01-graphs_hamiltonian_cycle.zig
120 lines (103 loc) · 3.56 KB
/
01-graphs_hamiltonian_cycle.zig
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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
const std = @import("std");
const print = std.debug.print;
/// Number of vertices in the graph
const N = 5;
/// A utility function to print the solution
fn printSolution(path: [N]i32) void {
print("Solution Exists: ", .{});
for (0..N) |i| {
print("{d} ", .{path[i]});
}
// Print the first vertex again to show the complete cycle
print("{d}\n\n", .{path[0]});
}
/// A utility function to check if the vertex `v` can be added at index `pos`
/// in the Hamiltonian cycle constructed so far (stored in `path`)
fn isSafe(v: i32, graph: *[N][N]i32, path: [N]i32, pos: usize) bool {
// Check if this vertex is an adjacent vertex of the previously added vertex.
if (graph.*[@intCast(path[pos - 1])][@intCast(v)] == 0) return false;
// Check if the vertex has already been included.
for (0..pos) |i| {
if (path[i] == v) return false;
}
return true;
}
/// A recursive utility function to solve the Hamiltonian cycle problem
fn hamiltonianCycleUtil(graph: *[N][N]i32, path: *[N]i32, pos: usize) bool {
// Base case: If all vertices are included in the Hamiltonian cycle
if (pos == N) {
// And if there is an edge from the last included vertex to the first vertex
if (graph.*[@intCast(path[pos - 1])][@intCast(path[0])] == 1) {
return true;
} else {
return false;
}
}
// Try different vertices as the next candidate in the Hamiltonian cycle.
// We don't try for 0 as we included 0 as the starting point in hamiltonianCycle()
for (1..N) |v| {
const v_int: i32 = @intCast(v);
// Check if this vertex can be added to the Hamiltonian cycle
if (isSafe(v_int, graph, path.*, pos)) {
path.*[pos] = v_int;
// Recur to construct the rest of the path
if (hamiltonianCycleUtil(graph, path, pos + 1))
return true;
// If adding vertex `v` doesn't lead to a solution, then remove it
path.*[pos] = -1;
}
}
// If no vertex can be added to the Hamiltonian cycle constructed so far,
// then return false
return false;
}
/// This function solves the Hamiltonian cycle problem using backtracking.
/// It mainly uses `hamiltonianCycleUtil()` to solve the problem.
/// It returns false if there is no Hamiltonian cycle possible,
/// otherwise returns true and prints the path.
fn hamiltonianCycle(graph: *[N][N]i32) bool {
var path: [N]i32 = [_]i32{-1} ** N;
// Let us put vertex 0 as the first vertex in the path.
// If there is a Hamiltonian cycle,
// then the path can be started from any point
// of the cycle as the graph is undirected
path[0] = 0;
if (!hamiltonianCycleUtil(graph, &path, 1)) {
print("Solution does not exist\n\n", .{});
return false;
}
printSolution(path);
return true;
}
/// Main function
pub fn main() !void {
// Test case 1:
// (0)--(1)--(2)
// | / \ |
// | / \ |
// | / \ |
// (3)-------(4)
var graph1: [N][N]i32 = .{
.{ 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 },
};
_ = hamiltonianCycle(&graph1);
// Test case 2:
// (0)--(1)--(2)
// | / \ |
// | / \ |
// | / \ |
// (3) (4)
var graph2: [N][N]i32 = .{
.{ 0, 1, 0, 1, 0 },
.{ 1, 0, 1, 1, 1 },
.{ 0, 1, 0, 0, 1 },
.{ 1, 1, 0, 0, 0 },
.{ 0, 1, 1, 0, 0 },
};
print("Test Case 2:\n", .{});
_ = hamiltonianCycle(&graph2);
}