From 951221578a79194377ff05454a1b09a29b1ef413 Mon Sep 17 00:00:00 2001 From: Undeemiss Date: Wed, 20 Apr 2022 20:54:07 -0500 Subject: [PATCH] Implemented no solution case of 2-coloring contract checker Implemented a greedy 2-coloring algorithm to check whether a given graph is 2-colorable. The algorithm is only used if the player provides "[]" as their answer; other answers will be checked using the previously implemented validation code. --- src/data/codingcontracttypes.ts | 52 ++++++++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/src/data/codingcontracttypes.ts b/src/data/codingcontracttypes.ts index 8a3017b97..103ffd594 100644 --- a/src/data/codingcontracttypes.ts +++ b/src/data/codingcontracttypes.ts @@ -1308,7 +1308,7 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [ }, { name: "Proper 2-Coloring of a Graph", - difficulty: 6, + difficulty: 7, numTries: 5, desc: (data: [number, [number, number][]]): string => { return `test description: "${JSON.stringify(data)}"`; @@ -1355,10 +1355,54 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [ return [n + m, edges]; }, solver: (data: [number, [number, number][]], ans: string): boolean => { - //No solution case + //Case where the player believes there is no solution if (ans == "[]") { - //TODO: Check if there is no solution - return true; + //Helper function to get neighbourhood of a vertex + function neighbourhood(vertex: number): number[] { + const adjLeft = data[1].filter(([a, _]) => a == vertex).map(([_, b]) => b); + const adjRight = data[1].filter(([_, b]) => b == vertex).map(([a, _]) => a); + return adjLeft.concat(adjRight); + } + + //Verify that there is no solution by attempting to create a proper 2-coloring. + const coloring: (number | undefined)[] = Array(data[0]).fill(undefined); + while (coloring.some((val) => val === undefined)) { + //Color a vertex in the graph + const initialVertex: number = coloring.findIndex((val) => val === undefined); + coloring[initialVertex] = 0; + const frontier: number[] = [initialVertex]; + + //Propogate the coloring throughout the component containing v greedily + while (frontier.length > 0) { + const v: number = frontier.pop() || 0; + const neighbors: number[] = neighbourhood(v); + + //For each vertex u adjacent to v + for (const id in neighbors) { + const u: number = neighbors[id]; + + //Set the color of u to the opposite of v's color if it is new, + //then add u to the frontier to continue the algorithm. + if (coloring[u] === undefined) { + if (coloring[v] === 0) coloring[u] = 1; + else coloring[u] = 0; + + frontier.push(u); + } + + //Assert u,v do not have the same color + else if (coloring[u] === coloring[v]) { + //If u,v do have the same color, no proper 2-coloring exists, meaning + //the player was correct to say there is no proper 2-coloring of the graph. + return true; + } + } + } + } + + //If this code is reached, there exists a proper 2-coloring of the input + //graph, and thus the player was incorrect in submitting no answer. + return false; } //Sanitize player input