This commit is contained in:
parent
b9341bdecc
commit
77b24dd148
@ -1,7 +1,36 @@
|
||||
from collections import defaultdict
|
||||
from typing import Any, Iterator
|
||||
|
||||
from ..base import BaseSolver
|
||||
from ..tools.graphs import iter_max_cliques
|
||||
|
||||
|
||||
class Solver(BaseSolver):
|
||||
def solve(self, input: str) -> Iterator[Any]: ...
|
||||
def solve(self, input: str) -> Iterator[Any]:
|
||||
connections: dict[str, set[str]] = defaultdict(set)
|
||||
for row in input.splitlines():
|
||||
src, dst = row.split("-")
|
||||
connections[src].add(dst)
|
||||
connections[dst].add(src)
|
||||
|
||||
if self.files:
|
||||
content = "graph G {\n"
|
||||
for row in input.splitlines():
|
||||
src, dst = row.split("-")
|
||||
content += f"{src} -- {dst}\n"
|
||||
content += "}"
|
||||
self.files.create("graph.dot", content.encode(), False)
|
||||
|
||||
cliques: set[frozenset[str]] = set()
|
||||
|
||||
for node1, neighbors in connections.items():
|
||||
for node2 in neighbors:
|
||||
for node3 in connections[node2].intersection(neighbors):
|
||||
cliques.add(frozenset({node1, node2, node3}))
|
||||
|
||||
self.logger.info(f"found {len(cliques)} cliques of size 3")
|
||||
yield sum(any(node.startswith("t") for node in clique) for clique in cliques)
|
||||
|
||||
# clique = max(nx.algorithms.clique.find_cliques(G), key=len)
|
||||
clique = max(iter_max_cliques(connections), key=len)
|
||||
yield ",".join(sorted(clique))
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,32 @@
|
||||
kh-tc
|
||||
qp-kh
|
||||
de-cg
|
||||
ka-co
|
||||
yn-aq
|
||||
qp-ub
|
||||
cg-tb
|
||||
vc-aq
|
||||
tb-ka
|
||||
wh-tc
|
||||
yn-cg
|
||||
kh-ub
|
||||
ta-co
|
||||
de-co
|
||||
tc-td
|
||||
tb-wq
|
||||
wh-td
|
||||
ta-ka
|
||||
td-qp
|
||||
aq-cg
|
||||
wq-ub
|
||||
ub-vc
|
||||
de-ta
|
||||
wq-aq
|
||||
wq-vc
|
||||
wh-yn
|
||||
ka-de
|
||||
kh-ta
|
||||
co-tc
|
||||
wh-qp
|
||||
tb-vc
|
||||
td-yn
|
@ -1,5 +1,13 @@
|
||||
import heapq
|
||||
from typing import Callable, Iterable, TypeVar, overload
|
||||
from typing import (
|
||||
Callable,
|
||||
Iterable,
|
||||
Iterator,
|
||||
Mapping,
|
||||
TypeVar,
|
||||
cast,
|
||||
overload,
|
||||
)
|
||||
|
||||
_Node = TypeVar("_Node")
|
||||
|
||||
@ -116,3 +124,63 @@ def dijkstra(
|
||||
return preds
|
||||
|
||||
return preds.get(target, None)
|
||||
|
||||
|
||||
def iter_max_cliques(
|
||||
neighbors: Mapping[_Node, Iterable[_Node]], nodes: Iterable[_Node] | None = None
|
||||
) -> Iterator[list[_Node]]:
|
||||
"""
|
||||
Find max cliques from the given set of neighbors containing the given set of nodes.
|
||||
|
||||
This is simply the networkx implementation with typing (and using a simple mapping
|
||||
to avoid requiring networkx).
|
||||
"""
|
||||
if len(neighbors) == 0:
|
||||
return
|
||||
|
||||
# remove the node itself from the neighbors
|
||||
adj = {u: {v for v in neighbors[u] if v != u} for u in neighbors}
|
||||
|
||||
# Initialize Q with the given nodes and subg, cand with their nbrs
|
||||
Q: list[_Node | None] = list(nodes or [])
|
||||
cand = set(neighbors)
|
||||
for node in Q:
|
||||
if node not in cand:
|
||||
raise ValueError(f"The given `nodes` {nodes} do not form a clique")
|
||||
cand &= adj[node]
|
||||
|
||||
if not cand:
|
||||
yield cast(list[_Node], Q[:])
|
||||
return
|
||||
|
||||
subg = cand.copy()
|
||||
stack: list[tuple[set[_Node], set[_Node], set[_Node]]] = []
|
||||
Q.append(None)
|
||||
|
||||
u = max(subg, key=lambda u: len(cand & adj[u]))
|
||||
ext_u = cand - adj[u]
|
||||
|
||||
try:
|
||||
while True:
|
||||
if ext_u:
|
||||
q = ext_u.pop()
|
||||
cand.remove(q)
|
||||
Q[-1] = q
|
||||
adj_q = adj[q]
|
||||
subg_q = subg & adj_q
|
||||
if not subg_q:
|
||||
yield cast(list[_Node], Q[:])
|
||||
else:
|
||||
cand_q = cand & adj_q
|
||||
if cand_q:
|
||||
stack.append((subg, cand, ext_u))
|
||||
Q.append(None)
|
||||
subg = subg_q
|
||||
cand = cand_q
|
||||
u = max(subg, key=lambda u: len(cand & adj[u]))
|
||||
ext_u = cand - adj[u]
|
||||
else:
|
||||
Q.pop()
|
||||
subg, cand, ext_u = stack.pop()
|
||||
except IndexError:
|
||||
pass
|
||||
|
Loading…
Reference in New Issue
Block a user