def reduction2(g: MultiGraph, w: set, h: MultiGraph, k: int) -> (int, int, bool): for v in h.nodes(): # Check if G[W ∪ {v}] contains a cycle. if not is_forest(g.subgraph(w.union({v}))): g.remove_node(v) h.remove_nodes_from([v]) return (k - 1, v, True) return (k, None, False)
def fvs_disjoint(g: MultiGraph, w: set, k: int) -> set: # Check that G[W] is a forest. # If it isn't, then a solution X not using W can't remove W's cycles. if not is_forest(g.subgraph(w)): return None # Apply reductions exhaustively. k, soln_redux = apply_reductions(g, w, k) # If k becomes negative, it indicates that the reductions included # more than k vertices, hence no solution of size <= k exists. if k < 0: return None # If G has been reduced to nothing and k is >= 0 then the solution generated by the reductions # is already optimal. if len(g) == 0: return soln_redux # Find an x in H of degree at most 1. h = graph_minus(g, w) x = None for v in h.nodes(): if h.degree(v) <= 1: x = v break assert x is not None # Branch. # G is copied in the left branch (as it is modified), but passed directly in the right. soln_left = fvs_disjoint(graph_minus(g, {x}), w, k - 1) if soln_left is not None: return soln_redux.union(soln_left).union({x}) soln_right = fvs_disjoint(g, w.union({x}), k) if soln_right is not None: return soln_redux.union(soln_right) return None
def is_fvs(g: MultiGraph, w) -> bool: h = graph_minus(g, w) return ((len(h) == 0) or is_forest(h))