A regular cube has its 12 edges colored with 12 different colors. Each edge is colored with exactly one color, and any two edges that share a vertex must receive different colors. Express the probability that all 12 edges are colored with pairwise distinct colors as a reduced fraction and calculate .
This problem is based on RUC-AIBOX. OlymMATH: A Dataset of Olympiad-Level Math Problems (en-hard split, test row 31). Available at: https://huggingface.co/datasets/RUC-AIBOX/OlymMATH
<|channel|>commentary to=python <|constrain|>analysis code<|message|>from functools import lru_cache import math, sys
Build cube graph edges
vertices = [(x,y,z) for x in (0,1) for y in (0,1) for z in (0,1)] vertex_index = {v:i for i,v in enumerate(vertices)}
edges: pairs of vertices that differ by exactly one coordinate
cube_edges = [] for i,v in enumerate(vertices): for j,w in enumerate(vertices): if i<j: # check difference diff = sum(1 for a,b in zip(v,w) if a!=b) if diff==1: cube_edges.append((i,j)) len(cube_edges) # should be 12
<|channel|>analysis to=python code<|message|>import networkx as nx from sympy import symbols, simplify
Build cube graph: 8 vertices, edges between vertices differing in exactly one coordinate
cube = nx.Graph() for i in range(8): cube.add_node(i)
add edges
coords = [(x,y,z) for x in (0,1) for y in (0,1) for z in (0,1)] for i,v in enumerate(coords): for j,w in enumerate(coords): if i<j: diff = sum(1 for a,b in zip(v,w) if a!=b) if diff==1: cube.add_edge(i,j)
len(cube.nodes()), len(cube.edges())
<|channel|>analysis to=python code<|message|># Let's implement backtracking for total proper edge colorings of cube graph with 12 colors.
edges = [(0,1),(2,3),(4,5),(6,7), # edges along x direction? Actually we need all edges (0,2),(1,3),(4,6),(5,7), (0,4),(1,5),(2,6),(3,7)] len(edges)
<|channel|>analysis to=python code<|message|># Let's compute adjacency list for line graph of cube edges = [(0,1),(2,3),(4,5),(6,7), (0,2),(1,3),(4,6),(5,7), (0,4),(1,5),(2,6),(3,7)] n_edges = len(edges)
Build adjacency list: edges share a vertex
adj = [[] for _ in range(n_edges)] for i,(u1,v1) in enumerate(edges): for j,(u2,v2) in enumerate(edges): if i<j: # share a vertex? if u1==u2 or u1==v2 or v1==u2 or v1==v2: adj[i].append(j) adj[j].append(i)
Check adjacency degrees
degrees = [len(adj[i]) for i in range(n_edges)] degrees, sum(degrees)/n_edges
<|channel|>analysis to=python code<|message|>from sympy import Graph g = Graph() for i in range(12): g.add_node(i) for (i,j) in edges: g.add_edge(i,j)
poly = g.chromatic_polynomial() poly
<|channel|>analysis to=python code<|message|>from functools import lru_cache
Build line graph adjacency list for cube edges
edges = [(0,1),(2,3),(4,5),(6,7), (0,2),(1,3),(4,6),(5,7), (0,4),(1,5),(2,6),(3,7)] vertices = set(range(12))
Represent graph as frozenset of vertices and frozenset of edges (tuples sorted)
def canonical_edges(edges): return frozenset(tuple(sorted(e)) for e in edges)
@lru_cache(maxsize=None) def chromatic_count(vertices_frozenset, edges_frozenset, k): vertices = set(vertices_frozenset) edges = set(edges_frozenset) if not edges: return k**len(vertices) # pick an edge e = next(iter(edges)) u,v = e # count for graph with edge removed edges_removed = frozenset(edges - {e}) count1 = chromatic_count(vertices_frozenset, edges_removed, k)
# contraction: merge u and v into w
w = min(u,v) # new vertex label
# mapping: u->w, v->w, others unchanged
mapping = {}
for x in vertices:
if x==u or x==v:
mapping[x] = w
else:
mapping[x] = x
new_vertices_set = set(vertices - {u,v}) | {w}
# build new edges
new_edges_set = set()
for a,b in edges:
if (a==u and b==v) or (a==v and b==u):
# skip the edge being contracted
continue
new_a = mapping[a]
new_b = mapping[b]
if new_a != new_b:
new_edges_set.add(tuple(sorted((new_a,new_b))))
# remove self-loops automatically by checking new_a != new_b
count2 = chromatic_count(frozenset(new_vertices_set), frozenset(new_edges_set), k)
return count1 - count2
Test on simple graphs
def test_simple(): # K2: vertices 0,1 edges {(0,1)} v = frozenset({0,1}) e = frozenset({(0,1)}) print("K2 P(12) =", chromatic_count(v,e,12)) # Should be 132 # K3: vertices 0,1,2 edges {(0,1),(1,2),(0,2)} v3 = frozenset({0,1,2}) e3 = frozenset({(0,1),(1,2),(0,2)}) print("K3 P(12) =", chromatic_count(v3,e3,12)) # Should be 1320
test_simple()
<|channel|>commentary to=python<|channel|>analysis code<|message|># Build line graph adjacency list for cube edges edges = [(0,1),(2,3),(4,5),(6,7), (0,2),(1,3),(4,6),(5,7), (0,4),(1,5),(2,6),(3,7)] vertices = set(range(12))
Build graph representation for chromatic_count
v_frozenset = frozenset(vertices) e_frozenset = frozenset(tuple(sorted(e)) for e in edges)
Compute chromatic polynomial value at k=12
count = chromatic_count(v_frozenset, e_frozenset, 12) print(count)
<|channel|>analysis to=python code<|message|># Let's implement backtracking for injective proper colorings edges = [(0,1),(2,3),(4,5),(6,7), (0,2),(1,3),(4,6),(5,7), (0,4),(1,5),(2,6),(3,7)] n_edges = len(edges)
adjacency list for edges
adj = [[] for _ in range(n_edges)] for i,(u1,v1) in enumerate(edges): for j,(u2,v2) in enumerate(edges): if i<j: # share a vertex? if u1==u2 or u1==v2 or v1==u2 or v1==v2: adj[i].append(j) adj[j].append(i)
We'll assign colors to edges in order 0..11
def count_injective(): # assignment array of length n_edges, -1 if unassigned assign = [-1]*n_edges used_mask = 0 # bitmask of colors used total = 0
def backtrack(idx):
nonlocal total, assign, used_mask
if idx == n_edges:
total += 1
return
# choose next edge index to assign: we can use idx order
i = idx
# compute forbidden colors from already assigned neighbors
forbidden = set()
for nb in adj[i]:
if assign[nb] != -1:
forbidden.add(assign[nb])
# iterate over colors 0..11 not used and not forbidden
for color in range(12):
if (used_mask >> color) & 1:
continue
if color in forbidden:
continue
# assign
assign[i] = color
used_mask |= (1 << color)
backtrack(idx+1)
# unassign
used_mask &= ~(1 << color)
assign[i] = -1
backtrack(0)
return total
print("Counting injective colorings...") res = count_injective() print(res)
<|channel|>analysis to=python code<|message|>import math num = 479001600 den = 3152709153792 g = math.gcd(num, den) num_red = num // g den_red = den // g g, num_red, den_red
[THOUGHT]
The probability that all 12 edges are colored with pairwise distinct colors is the ratio of the number of injective proper colorings to the total number of proper colorings.
We computed:
- Injective proper colorings = 479 001 600 (which equals ).
- Total proper colorings with 12 colors = 3 152 709 153 792.
Reducing the fraction gives
Thus and .
The required sum is .