From 0f3914d858cf7bdce20895d79efe286f45e7e5cf Mon Sep 17 00:00:00 2001 From: martapanc Date: Mon, 23 Dec 2024 17:58:36 +0100 Subject: [PATCH] 2024D23: part 2 --- 2024/src/2024/day23/day23.test.ts | 4 +- 2024/src/2024/day23/day23.ts | 63 +++++++++++++++++++++++++++++-- 2 files changed, 61 insertions(+), 6 deletions(-) diff --git a/2024/src/2024/day23/day23.test.ts b/2024/src/2024/day23/day23.test.ts index 2741144..c920526 100644 --- a/2024/src/2024/day23/day23.test.ts +++ b/2024/src/2024/day23/day23.test.ts @@ -7,7 +7,7 @@ describe('2024 Day 23', () => { }); test('Part 2', async () => { - expect(await part2('testInput1')).toEqual(31); - expect(await part2('input')).toEqual(29379307); + expect(await part2('testInput1')).toEqual("co,de,ka,ta"); + expect(await part2('input')).toEqual("bg,bl,ch,fn,fv,gd,jn,kk,lk,pv,rr,tb,vw"); }); }); \ No newline at end of file diff --git a/2024/src/2024/day23/day23.ts b/2024/src/2024/day23/day23.ts index c840ffa..a22c8a2 100644 --- a/2024/src/2024/day23/day23.ts +++ b/2024/src/2024/day23/day23.ts @@ -6,10 +6,10 @@ export async function part1(inputFile: string) { } export async function part2(inputFile: string) { - return await day23(inputFile); + return await day23(inputFile, findLargestParty); } -async function day23(inputFile: string, calcFn?: (lines: string[]) => number) { +async function day23(inputFile: string, calcFn?: (lines: string[]) => number | string) { const inputPath = path.join(__dirname, inputFile); const lines = await readInputLineByLine(inputPath); @@ -17,7 +17,60 @@ async function day23(inputFile: string, calcFn?: (lines: string[]) => number) { } function findComputerTriplets(lines: string[]) { - const adjacencyList: { [key: string]: Set} = {}; + const adjacencyList = getAdjacencyList(lines); + + return getTrianglesStartingWithT(adjacencyList); +} + +// Bron–Kerbosch Algorithm: +// It operates on three sets: +// - R (Current Clique): Nodes included in the current clique. +// - P (Candidates): Nodes that can be added to the current clique. +// - X (Excluded): Nodes already considered and excluded from the current clique. +// At each step: +// - If P and X are empty, R is a maximal clique. +// - A pivot is selected to reduce the search space and optimize performance. +// Recursive calls refine these sets to explore possible cliques. + +function findLargestParty(lines: string[]) { + const adjacencyList = getAdjacencyList(lines); + + const findLargestParties = (adjacencyList: { [key: string]: Set }) => { + const parties: string[][] = []; + + const bronKerbosch = (r: Set, p: Set, x: Set) => { + if (p.size === 0 && x.size === 0) { + parties.push([...r]); + return; + } + + const pivot = p.size > 0 ? [...p][0] : null; + const pivotNeighbors = pivot ? adjacencyList[pivot] : new Set(); + + for (const node of [...p].filter((n) => !pivotNeighbors.has(n))) { + bronKerbosch( + new Set([...r, node]), + new Set([...p].filter((n) => adjacencyList[node].has(n))), + new Set([...x].filter((n) => adjacencyList[node].has(n))), + ); + p.delete(node); + x.add(node); + } + } + + bronKerbosch(new Set(), new Set(Object.keys(adjacencyList)), new Set()); + return parties; + } + + const findLargestParty = (parties: string[][]) => { + return parties.reduce((max, party) => (party.length > max.length ? party : max), []); + } + + return findLargestParty(findLargestParties(adjacencyList)).sort().join(","); +} + +function getAdjacencyList(lines: string[]) { + const adjacencyList: { [key: string]: Set } = {}; for (const connection of lines) { const [a, b] = connection.split("-"); if (!adjacencyList[a]) @@ -28,7 +81,10 @@ function findComputerTriplets(lines: string[]) { adjacencyList[a].add(b); adjacencyList[b].add(a); } + return adjacencyList; +} +function getTrianglesStartingWithT(adjacencyList: { [p: string]: Set }) { const triangles: Set = new Set(); let trianglesStartingWithT = 0; for (const [node, neighbors] of Object.entries(adjacencyList)) { @@ -46,7 +102,6 @@ function findComputerTriplets(lines: string[]) { } } } - [...triangles].forEach((triangle: string) => { const split = triangle.split(",") if (split.some(s => s.startsWith("t"))) {