====== graph.py ======
===== imports and globals =====
import collections
from collections.abc import (
Callable,
Collection,
Iterable,
Mapping,
MutableSequence,
Sequence,
)
import heapq
import itertools
import operator
import sys
from typing import cast, Literal, TypeAlias
from teflib import disjointset
Node: TypeAlias = int
Graph: TypeAlias = Sequence[Iterable[int]]
WGraph: TypeAlias = Sequence[Mapping[int, float]]
EdgeGraph: TypeAlias = list[tuple[int, int]]
EdgeDiGraph: TypeAlias = list[tuple[int, int]]
EdgeWGraph: TypeAlias = list[tuple[int, int, float]]
MatGraph: TypeAlias = Sequence[Sequence[float]]
INF = float('inf')
===== create_graph_from_input =====
==== 코드 ====
# N create_graph_from_input
# I {"version": "0.1"}
def create_graph_from_input(
node_count: int,
edge_count: int,
*,
input_func: Callable[[], str] | None = None,
is_undirected=True,
base: Literal[0, 1] = 1,
) -> list[list[Node]]:
"""Create an undirected graph by reading edges from stdin."""
input_func = input_func or sys.stdin.readline
graph: list[list[Node]] = [[] for _ in range(node_count)]
for _ in range(edge_count):
u, v = [int(x) - base for x in input_func().split()]
graph[u].append(v)
if is_undirected:
graph[v].append(u)
return graph
==== 설명 ====
* [[ps:그래프]] 참고
==== 이 코드를 사용하는 문제 ====
* 너무 많아서 생략
===== two_coloring =====
==== 코드 ====
# N two_coloring
# I {"version": "0.3"}
def two_coloring(graph: Graph) -> list[bool]:
"""Find 2-coloring of graph in O(|V|+|E|).
Note that a graph is 2-colorable iff it's bipartite.
Args:
graph: An undirected graph.
Returns:
A list mapping nodes to color represented as boolean (True or False).
Raises:
ValueError: If the graph is not 2-colorable (= not bipartite).
"""
color: list[bool | None] = [None] * len(graph)
for source, col in enumerate(color):
if col is not None:
continue
color[source] = True
stack = [source]
while stack:
u = stack.pop()
col_u = color[u]
for v in graph[u]:
if color[v] is None:
color[v] = not col_u
stack.append(v)
elif color[v] == col_u:
raise ValueError('Graph is not 2-colorable.')
return cast(list[bool], color)
==== 설명 ====
* [[ps:2색 색칠]] 참고
==== 이 코드를 사용하는 문제 ====
---- struct table ----
schema: ps
cols: site, prob_id, %title%, prob_level
filter: teflib ~ *[graph.two_coloring]*
csv: 0
----
===== minimum_spanning_tree =====
==== 코드 ====
# N minimum_spanning_tree
# I {"version": "1.01", "import": ["operator"], "func": ["disjointset.DisjointSet"], "const": ["INF", "EdgeWGraph"]}
def minimum_spanning_tree(graph_edges: EdgeWGraph,
node_count: int) -> EdgeWGraph:
"""Returns the minimum spanning tree of given graph."""
dsu = disjointset.DisjointSet(node_count)
component_count, mst_edges = node_count, []
for e in sorted(graph_edges, key=operator.itemgetter(2)):
u, v, _ = e
if dsu.union_if_disjoint(u, v):
mst_edges.append(e)
component_count -= 1
if component_count == 1:
return mst_edges
raise ValueError('Graph is not connected')
==== 설명 ====
* [[ps:최소 신장 트리]] 참고
==== 이 코드를 사용하는 문제 ====
---- struct table ----
schema: ps
cols: site, prob_id, %title%, prob_level
filter: teflib ~ *[graph.minimum_spanning_tree]*
csv: 0
----
===== minimum_spanning_tree_dense =====
==== 코드 ====
# N minimum_spanning_tree_dense
# I {"version": "1.1", "import": ["operator"], "const": ["EdgeWGraph", "MatGraph", "INF"]}
def minimum_spanning_tree_dense(mat_graph) -> EdgeWGraph:
"""Returns MST of given complete undirected graph.
Implementation is based on Prim's algorithm, running in O(V^2)."""
weights = {x: INF for x in range(1, len(mat_graph))}
par = [None] * len(mat_graph)
min_weight_node = 0
mst_edges = []
for _ in range(len(mat_graph) - 1):
p = min_weight_node
weights_from_p = mat_graph[p]
min_weight = INF
for v, weight_v in weights.items():
if (w := weights_from_p[v]) < weight_v:
par[v], weights[v], weight_v = p, w, w
if weight_v < min_weight:
min_weight_node, min_weight = v, weight_v
mst_edges.append((par[min_weight_node], min_weight_node, min_weight))
del weights[min_weight_node]
return sorted(mst_edges, key=operator.itemgetter(2))
==== 설명 ====
* [[ps:최소 신장 트리]] 참고
==== 이 코드를 사용하는 문제 ====
---- struct table ----
schema: ps
cols: site, prob_id, %title%, prob_level
filter: teflib ~ *[graph.minimum_spanning_tree_dense]*
csv: 0
----