/// <summary> /// Reconstruct the calculated tree, by backtracking the results /// </summary> /// <param name="graph"></param> public static void ConstructTreeDepthTree(SubGraph graph) { if (graph.size == 1) { return; } short currentNode = (short)(_table[graph.nodes] >> 16); BitArray newNodes = new BitArray(graph.nodes) { [currentNode] = false }; foreach (SubGraph cc in ConnectedComponents(currentNode, newNodes)) { // Leafs aren't saved in the table. if (cc.size == 1) { _nodeLocations[FirstNode(cc.nodes)] = (short)(currentNode + 1); continue; } if (IsTree(cc)) { // Path is a special type of tree // Paths require a different reconstruction if (IsPath(cc.nodes)) { ConstructPath(cc.size, cc.nodes, currentNode); continue; } short treeRoot = _adjacencyList[currentNode].Find(v => cc.nodes[v]); _nodeLocations[treeRoot] = (short)(currentNode + 1); ConstructSubTree(CreateTree(cc.nodes, treeRoot), _treeRanks[cc.nodes]); continue; } _nodeLocations[_table[cc.nodes] >> 16] = (short)(currentNode + 1); ConstructTreeDepthTree(cc); } }
/// <summary> /// Check if a sub-graph is a tree /// </summary> /// <param name="graph">The input graph.<br /> NOTE: This has to be a connected graph.</param> /// <returns></returns> private static bool IsTree(SubGraph graph) { // Check if the graph of n vertices has n - 1 edges. return(graph.edges == graph.size - 1); }
public static void Main(string[] args) { #if DEBUG // Try to load file when needed if (args != null && args.Length > 0) { StreamReader inputFile; using (inputFile = new StreamReader(args[0])) { Console.SetIn(inputFile); } } #endif // Load the graph ReadGraph(); // Fill nodes by degree array and sort _nodesByDegree = new short[_graphSize]; for (short i = 0; i < _graphSize; i++) { _nodesByDegree[i] = i; } // Sort the nodes by degree Array.Sort(_nodesByDegree, (n1, n2) => _adjacencyList[n2].Count.CompareTo(_adjacencyList[n1].Count)); // Init memorization 'array' _table = new Dictionary <BitArray, int>(new BitArrayEqualityComparer()); // Init tree ranks dictionary _treeRanks = new Dictionary <BitArray, short[]>(new BitArrayEqualityComparer()); // Run solver SubGraph fullGraph = new SubGraph( new BitArray(_graphSize, true), _graphSize, _graphEdges, 1 ); // Try if a tree-depth below a certain number can be found. short currentTry = (short)(Math.Floor(Math.Log(fullGraph.size, 2)) + 2); int result = 0; _table[fullGraph.nodes] = short.MaxValue; while ((_table[fullGraph.nodes] & 0xFFFF) == short.MaxValue) { // Try to get the tree-depth result = TreeDepth(fullGraph, currentTry); // Increase the current try currentTry = (short)(currentTry * 1.5); } // Reconstruct tree _nodeLocations = new short[_graphSize]; ConstructTreeDepthTree(fullGraph); // Write the results Console.WriteLine(result); foreach (short node in _nodeLocations) { Console.WriteLine(node); } #if DEBUG Console.ReadLine(); #endif }
public static int TreeDepth(SubGraph graph, short bestResult = short.MaxValue, short from = -1) { if (_table.ContainsKey(graph.nodes)) { int res = _table[graph.nodes]; if ((res & 0xFFFF) < short.MaxValue || (res >> 16) >= bestResult ) { return(res & 0xFFFF); } } // Graph is just a single node if (graph.size == 1) { return(1); } // Graph is a tree if (IsTree(graph)) { int log = (int)Math.Log(graph.size, 2) + 1; if (log > bestResult) { return(short.MaxValue); } // A path is special type of tree if (IsPath(graph.nodes)) // Graph is a path { return(log); } // Graph is not a path, but still a tree. // Find a root for the tree short treeRoot = _adjacencyList[from].Find(v => graph.nodes[v]); // Create the space to write the ranks to short[] treeRank = new short[_graphSize]; // Set the tree-ranks list _treeRanks[graph.nodes] = treeRank; // Get rank of the tree int rank = CriticalRankTree(CreateTree(graph.nodes, treeRoot), treeRank).GetMax(); // Save the rank to the table _table[graph.nodes] = (from << 16) | rank; // Return the rank return(rank); } // The current best result // NOTE: The tree-depth cannot be bigger than the amount of nodes in the graph. int result = Math.Min(bestResult, graph.size); // The root that we chose to achieve this result int root = -1; foreach (short i in _nodesByDegree) { if (!graph.nodes[i]) { continue; } // Remove node i from the graph BitArray newNodes = new BitArray(graph.nodes) { [i] = false }; int size = 0; // Go through connected components foreach (SubGraph cc in ConnectedComponents(i, newNodes)) { // The tree-depth if the component has te be at least the size of // a path that it contains. if (result < (short)Math.Log(cc.pathSize, 2) + 1) { size = short.MaxValue; break; } // NOTE: The current value of 'result' is our best solution yet int td = TreeDepth(cc, (short)(result - 1), i); // ReSharper disable once InvertIf if (td > size) { size = td; // If the current tree-depth is also bigger than our best result yet, // it is better to break the branch. if (td >= result) { break; } } } // Add the current node to the size size += 1; // ReSharper disable once InvertIf if (size <= result) // Found a better result { result = size; root = i; } } if (root == -1) { // Set the root as the best result used to get this result root = result; result = short.MaxValue; } _table[graph.nodes] = (root << 16) | result; // Return the result return(result); }