Problem p02580 (python)

Fixed submission:
H, W, M, *hw = map(int, open(0).read().split())
H_cnt = [0] * (H + 1)
W_cnt = [0] * (W + 1)
bombs = [(h, w) for h, w in zip(*[iter(hw)] * 2)]
for h, w in bombs:
    H_cnt[h] += 1
    W_cnt[w] += 1

H_max_cnt = max(H_cnt)
W_max_cnt = max(W_cnt)

H_max = {i for i in range(1, H + 1) if H_cnt[i] == H_max_cnt}
W_max = {i for i in range(1, W + 1) if W_cnt[i] == W_max_cnt}

comb_cnt = len(H_max) * len(W_max)
for h, w in bombs:
    if H_cnt[h] == H_max_cnt and W_cnt[w] == W_max_cnt:
        comb_cnt -= 1

ans = H_max_cnt + W_max_cnt
print(ans if comb_cnt else ans - 1)

Buggy submission (verdict: Runtime Error):
from abc import abstractmethod
from collections import defaultdict


class Edge:
    def __init__(self):
        self.flow = 0
        self.residual: Edge
        self.from_node = None
        self.to_node = None
        self.capacity = None

    @classmethod
    def by_nodes(cls, from_node, to_node, capacity):
        c = cls()
        c.connect(from_node, to_node, capacity)
        return c

    def connect(self, from_node, to_node, capacity):
        self.from_node = from_node
        self.to_node = to_node
        self.capacity = capacity

    def is_residual(self):
        return self.capacity == 0

    def remaining_capacity(self):
        return self.capacity - self.flow

    def augument(self, bottle_neck):
        self.flow += bottle_neck
        self.residual.flow -= bottle_neck

    def __repr__(self):
        return f"{self.from_node}-({self.flow}/{self.capacity})->{self.to_node}"


class NetworkFlowSolverBase:
    def __init__(self, n, s, t):
        self.visited_token = 1
        self.visited = defaultdict(int)
        self.solved = False
        self.max_flow = 0
        self.graph = defaultdict(list)
        # n: the number of nodes in the graph including s(src) and t(sink)
        self.n = n
        # s: the index of the src node
        self.s = s
        # t: the index of the sink node
        self.t = t

    def add_edge(self, from_node, to_node, capacity):
        assert capacity >= 0, f"forward-edge capacity must be >= 0: input={capacity}"
        e_f = Edge.by_nodes(from_node, to_node, capacity)
        e_b = Edge.by_nodes(to_node, from_node, 0)
        e_f.residual = e_b
        e_b.residual = e_f
        self.graph[from_node].append(e_f)
        self.graph[to_node].append(e_b)

    def get_graph(self):
        self.execute()
        return self.graph

    def get_max_flow(self):
        self.execute()
        return self.max_flow

    def execute(self):
        if self.solved:
            return
        self.solve()
        self.solved = True

    @abstractmethod
    def solve(self):
        pass


class FordFulkersonDfsSover(NetworkFlowSolverBase):
    def __init__(self, n, s, t):
        super().__init__(n, s, t)

    def solve(self):
        while True:
            f = self.dfs(self.s, float("inf"))
            self.visited_token += 1
            self.max_flow += f
            if f == 0:
                break

    def dfs(self, nd, flow):
        if nd == self.t:
            return flow
        self.visited[nd] = self.visited_token

        for e in self.graph[nd]:
            if (
                e.remaining_capacity() > 0
                and self.visited[e.to_node] != self.visited_token
            ):
                bottle_neck = self.dfs(e.to_node, min(flow, e.remaining_capacity()))
                if bottle_neck > 0:
                    e.augument(bottle_neck)
                    return bottle_neck
        return 0


if __name__ == "__main__":
    H, W, M, *subjects = map(int, open(0).read().split())
    S = H + W
    T = H + W + 1
    g = FordFulkersonDfsSover(H + W + 2, S, T)
    for i in range(H):
        g.add_edge(S, i, 1)
    for i in range(W):
        g.add_edge(i + H, T, 1)
    [g.add_edge(h - 1, w - 1 + H, 1) for h, w in zip(*[iter(subjects)] * 2)]
    print(g.get_max_flow() + 1)