This commit is contained in:
		| @@ -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 | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user