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 day21 = @import("./day21/day21.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 day25 = @import("./day25/day25.zig");
|
||||
const utils = @import("utils.zig");
|
||||
|
||||
pub fn main() !void {
|
||||
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);
|
||||
|
||||
try day23.solve(input);
|
||||
try day25.solve(input);
|
||||
}
|
||||
|
Reference in New Issue
Block a user