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_eulerian_path.zig
139 lines (124 loc) · 3.6 KB
/
01-graphs_eulerian_path.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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
const std = @import("std");
const print = std.debug.print;
/// Number of vertices in the graph
const N = 5;
/// Maximum length of the path
const MAX_PATH_LENGTH = 20;
/// Find Eulerian Path in a graph
///
/// # Parameters
///
/// - `graph`: Adjacency matrix of the graph
fn findPath(graph: *[N][N]i32) void {
var numofadj: [N]i32 = [_]i32{0} ** N;
var stack: [N]i32 = [_]i32{0} ** N;
var path: [MAX_PATH_LENGTH]i32 = [_]i32{0} ** MAX_PATH_LENGTH;
var top: usize = 0;
var path_length: usize = 0;
// Find out number of edges each vertex has
for (0..N) |i| {
for (0..N) |j| {
numofadj[i] += graph.*[i][j];
}
}
// Find out how many vertices have an odd number of edges
var startpoint: usize = 0;
var numofodd: i32 = 0;
var idx_i: usize = N;
while (idx_i > 0) : (idx_i -= 1) {
const idx = idx_i - 1;
if (@mod(numofadj[idx], 2) == 1) {
numofodd += 1;
startpoint = idx;
}
}
// If the number of vertices with odd number of edges is greater than two, return "No Solution".
if (numofodd > 2) {
print("No Solution\n", .{});
return;
}
// Initialize empty stack and path; take the starting current as discussed
var cur: usize = startpoint;
// Loop will run until there is an element in the stack or current vertex has some neighbor.
while (top > 0 or numofadj[cur] > 0) {
// If current node has no neighbors, add it to path and pop stack; set new current to the popped element
if (numofadj[cur] == 0) {
path[path_length] = @intCast(cur);
path_length += 1;
if (top > 0) {
top -= 1;
cur = @intCast(stack[top]);
} else {
break;
}
}
// If the current vertex has at least one neighbor, add the current vertex to stack,
// remove the edge between them, and set the current to its neighbor.
else {
for (0..N) |j| {
if (graph.*[cur][j] == 1) {
stack[top] = @intCast(cur);
top += 1;
graph.*[cur][j] = 0;
graph.*[j][cur] = 0;
numofadj[cur] -= 1;
numofadj[j] -= 1;
cur = j;
break;
}
}
}
}
// Add the last vertex to the path
path[path_length] = @intCast(cur);
path_length += 1;
// Print the path
var idx: usize = path_length;
while (idx > 0) : (idx -= 1) {
print("{d} -> ", .{path[idx - 1]});
}
print("\n", .{});
}
/// Main function
pub fn main() !void {
// Test case 1:
// 0 --- 1
// | | \
// | 2--3
// 4
var graph1: [N][N]i32 = .{
.{ 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 },
};
print("Test Case 1:\n", .{});
findPath(&graph1);
// Test case 2:
// 0 -- 1 -- 2
// /| / \ | \
// 3--4 5
var graph2: [N][N]i32 = .{
.{ 0, 1, 0, 1, 1 },
.{ 1, 0, 1, 0, 1 },
.{ 0, 1, 0, 1, 1 },
.{ 1, 0, 1, 0, 0 },
.{ 1, 1, 1, 0, 0 },
};
print("Test Case 2:\n", .{});
findPath(&graph2);
// Test case 3:
// 0 --- 1
// /|\ |\
// 2 4---5 3
var graph3: [N][N]i32 = .{
.{ 0, 1, 1, 0, 1 },
.{ 1, 0, 0, 1, 1 },
.{ 1, 0, 0, 1, 0 },
.{ 0, 1, 1, 0, 1 },
.{ 1, 1, 0, 1, 0 },
};
print("Test Case 3:\n", .{});
findPath(&graph3);
}