This commit is contained in:
parent
b9341bdecc
commit
77b24dd148
@ -1,7 +1,36 @@
|
|||||||
|
from collections import defaultdict
|
||||||
from typing import Any, Iterator
|
from typing import Any, Iterator
|
||||||
|
|
||||||
from ..base import BaseSolver
|
from ..base import BaseSolver
|
||||||
|
from ..tools.graphs import iter_max_cliques
|
||||||
|
|
||||||
|
|
||||||
class Solver(BaseSolver):
|
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
|
import heapq
|
||||||
from typing import Callable, Iterable, TypeVar, overload
|
from typing import (
|
||||||
|
Callable,
|
||||||
|
Iterable,
|
||||||
|
Iterator,
|
||||||
|
Mapping,
|
||||||
|
TypeVar,
|
||||||
|
cast,
|
||||||
|
overload,
|
||||||
|
)
|
||||||
|
|
||||||
_Node = TypeVar("_Node")
|
_Node = TypeVar("_Node")
|
||||||
|
|
||||||
@ -116,3 +124,63 @@ def dijkstra(
|
|||||||
return preds
|
return preds
|
||||||
|
|
||||||
return preds.get(target, None)
|
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