// Uses depth-first search to check if the graph induced by the subgraph given as a parameter is connected // In other words, we retreive all edges from the original graph and check the subgraph for connectedness public static bool Connected(Graph graph, BitSet subgraph) { // Vertices that are visited Set<int> visited = new Set<int>(); // Stack of vertices yet to visit Stack<int> stack = new Stack<int>(); // Initial vertex int s = subgraph.First(); stack.Push(s); // Continue while there are vertices on the stack while (stack.Count > 0) { int v = stack.Pop(); // If we have not encountered this vertex before, then we check for all neighbors if they are part of the subgraph // If a neighbor is part of the subgraph it means that we have to push it on the stack to explore it at a later stage if (!visited.Contains(v)) { visited.Add(v); foreach (int w in graph.OpenNeighborhood(v)) if (subgraph.Contains(w)) stack.Push(w); } } // If we visited an equal number of vertices as there are vertices in the subgraph then the subgraph is connected return visited.Count == subgraph.Count; }
// Constructs the actual width values private static void ConstructTree(Graph graph, BitSet A) { long min = A.Count == 1 ? 0 : long.MaxValue; int n = graph.Size; int v = -1; // v is the vertex that if we remove it from A, we have the smallest number of neighbors BitSet optimal = new BitSet(0, n); Set<BitSet> subsets = new Set<BitSet>(new BitSet(0, n)); foreach (int a in A) { Set<BitSet> newSubsets = new Set<BitSet>(); foreach (BitSet j in subsets) { BitSet subset = j + a; BitSet inverse = A - subset; if (subset.Equals(A)) continue; // only consider strict subsets if (!Width.ContainsKey(subset)) ConstructTree(graph, subset); if (!Width.ContainsKey(inverse)) ConstructTree(graph, inverse); newSubsets.Add(subset); // add this for the next iteration long max = Math.Max(Width[subset], Width[inverse]); // either S or A\S will be the bottleneck if (max < min) { min = max; optimal = subset; // it doesn't matter if we take j + a or A - (j + a), since when retrieving the tree we split them anyway if (inverse.Count == 1) v = inverse.First(); } } subsets.AddRange(newSubsets); } v = v == -1 ? A.First() : v; BitSet nv = graph.OpenNeighborhood(v) * (graph.Vertices - (A - v)); Set<BitSet> un = new Set<BitSet>(); foreach (BitSet _base in Neighborhoods[A - v]) { un.Add(_base - v); // previous neighbor without v is a possible new neighborhood un.Add((_base - v) + nv); // previous neighbor without v, unioned with the neighborhood of v is a possible new neighborhood } Neighborhoods[A] = un; Cuts[A] = Neighborhoods[A].Count; Width[A] = Math.Max(min, Cuts[A]); // Actual possible width to get to this cut OptimalChild[A] = optimal; }