and we are done!
This commit is contained in:
175
AdventOfCode2023/src/day25/day25.zig
Normal file
175
AdventOfCode2023/src/day25/day25.zig
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const rand = std.crypto.random;
|
||||||
|
|
||||||
|
const print = std.debug.print;
|
||||||
|
const Map = std.StringHashMap;
|
||||||
|
const List = std.ArrayList([]const u8);
|
||||||
|
|
||||||
|
const VERTEX_NAME_SIZE = 3;
|
||||||
|
|
||||||
|
// Thanks to: https://www.geeksforgeeks.org/introduction-and-implementation-of-kargers-algorithm-for-minimum-cut/
|
||||||
|
//
|
||||||
|
// Struggled to understand the algorithm and the resource above helped so much.
|
||||||
|
|
||||||
|
const MincutReturn = struct {
|
||||||
|
mincut: usize,
|
||||||
|
vertex1: usize,
|
||||||
|
vertex2: usize,
|
||||||
|
};
|
||||||
|
|
||||||
|
const Edge = struct {
|
||||||
|
source: usize,
|
||||||
|
destination: usize,
|
||||||
|
};
|
||||||
|
|
||||||
|
const Subset = struct {
|
||||||
|
parent: usize,
|
||||||
|
rank: usize,
|
||||||
|
};
|
||||||
|
|
||||||
|
const Graph = struct {
|
||||||
|
allocator: std.mem.Allocator,
|
||||||
|
|
||||||
|
vertex_number: usize,
|
||||||
|
edge_number: usize,
|
||||||
|
|
||||||
|
edges: []Edge,
|
||||||
|
|
||||||
|
pub fn new(allocator: std.mem.Allocator, vertex_number: usize, edge_number: usize) Graph {
|
||||||
|
return Graph{
|
||||||
|
.allocator = allocator,
|
||||||
|
.vertex_number = vertex_number,
|
||||||
|
.edge_number = edge_number,
|
||||||
|
.edges = allocator.alloc(Edge, edge_number) catch unreachable,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find(subsets: []Subset, i: usize) usize {
|
||||||
|
if (subsets[i].parent != i) {
|
||||||
|
subsets[i].parent = find(subsets, subsets[i].parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
return subsets[i].parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn Union(subsets: []Subset, i: usize, j: usize) void {
|
||||||
|
const iroot = find(subsets, i);
|
||||||
|
const jroot = find(subsets, j);
|
||||||
|
|
||||||
|
if (subsets[iroot].rank < subsets[jroot].rank) {
|
||||||
|
subsets[iroot].parent = jroot;
|
||||||
|
} else {
|
||||||
|
if (subsets[iroot].rank > subsets[jroot].rank) {
|
||||||
|
subsets[jroot].parent = iroot;
|
||||||
|
}
|
||||||
|
// If ranks are same, then make one as root and
|
||||||
|
// increment its rank by one
|
||||||
|
else {
|
||||||
|
subsets[jroot].parent = iroot;
|
||||||
|
subsets[iroot].rank += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mincut(self: Graph) MincutReturn {
|
||||||
|
const vertex_number = self.vertex_number;
|
||||||
|
const edge_number = self.edge_number;
|
||||||
|
|
||||||
|
const copied_edges = self.allocator.alloc(Edge, self.edges.len) catch unreachable;
|
||||||
|
@memcpy(copied_edges, self.edges);
|
||||||
|
|
||||||
|
var subsets = self.allocator.alloc(Subset, vertex_number) catch unreachable;
|
||||||
|
for (0..vertex_number) |index| {
|
||||||
|
subsets[index] = Subset{ .parent = index, .rank = 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
var vertices = vertex_number;
|
||||||
|
while (vertices > 2) {
|
||||||
|
const i = rand.intRangeLessThan(usize, 0, edge_number);
|
||||||
|
|
||||||
|
const subset1 = find(subsets, copied_edges[i].source);
|
||||||
|
const subset2 = find(subsets, copied_edges[i].destination);
|
||||||
|
|
||||||
|
if (subset1 == subset2) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
vertices -= 1;
|
||||||
|
Union(subsets, subset1, subset2);
|
||||||
|
}
|
||||||
|
|
||||||
|
var cutedges: usize = 0;
|
||||||
|
for (0..edge_number) |i| {
|
||||||
|
const subset1 = find(subsets, copied_edges[i].source);
|
||||||
|
const subset2 = find(subsets, copied_edges[i].destination);
|
||||||
|
if (subset1 != subset2) {
|
||||||
|
cutedges += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var vertex1: usize = 0;
|
||||||
|
var vertex2: usize = 0;
|
||||||
|
|
||||||
|
const first_parent = subsets[0].parent;
|
||||||
|
|
||||||
|
for (subsets) |subset| {
|
||||||
|
if (subset.parent == first_parent) {
|
||||||
|
vertex1 += 1;
|
||||||
|
} else {
|
||||||
|
vertex2 += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return MincutReturn{ .mincut = cutedges, .vertex1 = vertex1, .vertex2 = vertex2 };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn solve(input: [][]const u8) !void {
|
||||||
|
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||||
|
const allocator = arena.allocator();
|
||||||
|
|
||||||
|
defer arena.deinit();
|
||||||
|
|
||||||
|
var number: usize = 0;
|
||||||
|
var name_to_num = Map(usize).init(allocator);
|
||||||
|
|
||||||
|
var edge_list = std.ArrayList(Edge).init(allocator);
|
||||||
|
defer edge_list.deinit();
|
||||||
|
|
||||||
|
for (input) |line| {
|
||||||
|
const vertex = line[0..VERTEX_NAME_SIZE];
|
||||||
|
const edges = line[VERTEX_NAME_SIZE + 2 ..];
|
||||||
|
var edges_tokenizer = std.mem.tokenizeSequence(u8, edges, " ");
|
||||||
|
|
||||||
|
if (name_to_num.get(vertex) == null) {
|
||||||
|
try name_to_num.put(vertex, number);
|
||||||
|
number += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const source_vertex = name_to_num.get(vertex).?;
|
||||||
|
|
||||||
|
while (edges_tokenizer.next()) |edge| {
|
||||||
|
if (name_to_num.get(edge) == null) {
|
||||||
|
try name_to_num.put(edge, number);
|
||||||
|
number += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const destination_vertex = name_to_num.get(edge).?;
|
||||||
|
|
||||||
|
try edge_list.append(Edge{ .source = source_vertex, .destination = destination_vertex });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var graph = Graph.new(allocator, number, edge_list.items.len);
|
||||||
|
graph.edges = try edge_list.toOwnedSlice();
|
||||||
|
|
||||||
|
const part1 = while (true) {
|
||||||
|
const mincut_values = graph.mincut();
|
||||||
|
|
||||||
|
if (mincut_values.mincut == 3) {
|
||||||
|
break mincut_values.vertex1 * mincut_values.vertex2;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
print("Part 1: {}\n", .{part1});
|
||||||
|
}
|
@ -20,14 +20,15 @@ const std = @import("std");
|
|||||||
// const day20 = @import("./day20/day20.zig");
|
// const day20 = @import("./day20/day20.zig");
|
||||||
// const day21 = @import("./day21/day21.zig");
|
// const day21 = @import("./day21/day21.zig");
|
||||||
// const day22 = @import("./day22/day22.zig");
|
// const day22 = @import("./day22/day22.zig");
|
||||||
const day23 = @import("./day23/day23.zig");
|
// const day23 = @import("./day23/day23.zig");
|
||||||
// const day24 = @import("./day24/day24.zig");
|
// const day24 = @import("./day24/day24.zig");
|
||||||
|
const day25 = @import("./day25/day25.zig");
|
||||||
const utils = @import("utils.zig");
|
const utils = @import("utils.zig");
|
||||||
|
|
||||||
pub fn main() !void {
|
pub fn main() !void {
|
||||||
const allocator = std.heap.page_allocator;
|
const allocator = std.heap.page_allocator;
|
||||||
const input = try utils.getInput("./src/day23/input.txt", allocator);
|
const input = try utils.getInput("./src/day25/input.txt", allocator);
|
||||||
defer allocator.free(input);
|
defer allocator.free(input);
|
||||||
|
|
||||||
try day23.solve(input);
|
try day25.solve(input);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user