| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798 |
- #!/usr/bin/env python3
- """课前零食:交替染色,并在冲突时给出一条奇环。"""
- from __future__ import annotations
- from collections import defaultdict, deque
- GOOD = [("A", "B"), ("A", "D"), ("C", "B"), ("C", "D"), ("E", "F")]
- BAD = [("A", "B"), ("B", "C"), ("C", "A"), ("C", "D")]
- def ask(prompt: str, default: str) -> str:
- try:
- return input(prompt).strip() or default
- except EOFError:
- return default
- def parse_edges(raw: str) -> list[tuple[str, str]]:
- result: list[tuple[str, str]] = []
- for token in raw.replace(",", ",").split(","):
- left, right = (part.strip() for part in token.split("-", 1))
- if not left or not right:
- raise ValueError("边应形如 A-B")
- result.append((left, right))
- return result
- def odd_cycle(u: str, v: str, parent: dict[str, str | None]) -> list[str]:
- up: list[str] = []
- cursor: str | None = u
- while cursor is not None:
- up.append(cursor)
- cursor = parent[cursor]
- vp: list[str] = []
- cursor = v
- while cursor is not None:
- vp.append(cursor)
- cursor = parent[cursor]
- position = {vertex: index for index, vertex in enumerate(up)}
- common = next(vertex for vertex in vp if vertex in position)
- left = up[:position[common] + 1]
- right = vp[:vp.index(common)]
- return left + list(reversed(right)) + [u]
- def color_graph(edges: list[tuple[str, str]]) -> None:
- graph: dict[str, list[str]] = defaultdict(list)
- for u, v in edges:
- graph[u].append(v)
- graph[v].append(u)
- color = {vertex: -1 for vertex in graph}
- parent: dict[str, str | None] = {}
- for start in sorted(graph):
- if color[start] != -1:
- continue
- color[start] = 0
- parent[start] = None
- queue: deque[str] = deque([start])
- print(f"\n从 {start} 染成 0 开始")
- while queue:
- u = queue.popleft()
- for v in graph[u]:
- if color[v] == -1:
- color[v] = 1 - color[u]
- parent[v] = u
- queue.append(v)
- print(f" 边 {u}-{v}:把 {v} 染成 {color[v]}")
- elif color[v] == color[u]:
- cycle = odd_cycle(u, v, parent)
- print(f" 冲突!{u} 与 {v} 都是颜色 {color[u]}。")
- print(" 一条奇环:", " -> ".join(cycle))
- return
- left = sorted(vertex for vertex, value in color.items() if value == 0)
- right = sorted(vertex for vertex, value in color.items() if value == 1)
- print("\n可二染:左侧(0)=", left, ";右侧(1)=", right)
- print("每个连通分量可以整体交换左右两侧。")
- def main() -> None:
- choice = ask("选择 g=可二染预设,b=奇环预设,c=自定义(回车为 g): ", "g").lower()
- if choice == "b":
- edges = BAD
- elif choice == "c":
- try:
- edges = parse_edges(ask("输入边 A-B,B-C: ", "A-B,B-C,C-A"))
- except (ValueError, IndexError) as error:
- print(f"格式不对:{error};改用奇环预设。")
- edges = BAD
- else:
- edges = GOOD
- print("边:", ", ".join(f"{u}-{v}" for u, v in edges))
- color_graph(edges)
- if __name__ == "__main__":
- main()
|