diff --git a/DKey.Algorithms.Tests/Graph/DFSTests.cs b/DKey.Algorithms.Tests/Graph/DFSTests.cs index 2e41f25..177cc34 100644 --- a/DKey.Algorithms.Tests/Graph/DFSTests.cs +++ b/DKey.Algorithms.Tests/Graph/DFSTests.cs @@ -24,6 +24,25 @@ public void Iterative_GivenGraph_ReturnsExpectedTraversal() Assert.That(traversal, Is.EqualTo(new[] { 0, 1, 3, 4, 2 })); } + + [Test] + public void IterativeWithExitExtiOn_GivenGraph_ReturnsExpectedTraversal() + { + var graph = new[] + { + new List { 1, 2 }, + new List { 3, 4 }, + new List(), + new List(), + new List(), + }; + var context = new DFSContext(graph, 0); + var traversal = new List(); + + DFS.IterativeWithExitAction(context, null, c => traversal.Add(c.CurrentVertex)); + + Assert.That(traversal, Is.EqualTo(new[] { 3, 4, 1, 2, 0 })); + } [Test] public void Recursive_GivenGraph_ReturnsExpectedTraversal() diff --git a/DKey.Algorithms.sln.DotSettings.user b/DKey.Algorithms.sln.DotSettings.user index d5e897a..9e6314d 100644 --- a/DKey.Algorithms.sln.DotSettings.user +++ b/DKey.Algorithms.sln.DotSettings.user @@ -1,7 +1,9 @@  + ForceIncluded ForceIncluded ForceIncluded ForceIncluded + ForceIncluded ForceIncluded ForceIncluded @@ -11,16 +13,7 @@ - <SessionState ContinuousTestingMode="0" IsActive="True" Name="Tests" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"> - <Not> - <And> - <Project Location="C:\Repos\github\DKey.Algorithms\Dkey.Algorithms.Tests" Presentation="&lt;DKey.Algorithms.Tests&gt;" /> - <TestAncestor> - <TestId>NUnit3x::705969DA-A152-47DC-9BB6-D5060B8D81F0::net7.0::DKey.Algorithms.Tests.Search.GoldenSectionSearchTests.Test_InvalidRange</TestId> - </TestAncestor> - </And> - </Not> -</SessionState> + diff --git a/DKey.Algorithms/DataStructures/Graph/DepthFirstSearch/DFS.cs b/DKey.Algorithms/DataStructures/Graph/DepthFirstSearch/DFS.cs index 8a3da51..74490f9 100644 --- a/DKey.Algorithms/DataStructures/Graph/DepthFirstSearch/DFS.cs +++ b/DKey.Algorithms/DataStructures/Graph/DepthFirstSearch/DFS.cs @@ -48,6 +48,61 @@ public static void Iterative(TContext context, Action? actio } } } + + /// + /// Iterative depth-first search with some action on the current context. + /// Use this for big graphs to avoid stack overflow. + /// Can be more memory efficient if you push vertices 1 by 1 tracking how many children ha been pushed, but this is easier to understand. + /// + public static void IterativeWithExitAction(TContext context, Action? enterAction = default, Action? exitAction = default, bool preallocate = false) where TContext : DFSContext + { + if(context.stopFlag) + return; + var stack = new Stack(preallocate ? context.Graph.Length : 0); + stack.Push(context.CurrentVertex); + context.VertexInfo[context.CurrentVertex] = (-1, 0); + + while (stack.Count > 0) + { + var currentVertex = stack.Peek(); + context.CurrentVertex = currentVertex; + + if (!context.Used.Contains(currentVertex)) + { + //On entering the vertex. + enterAction?.Invoke(context); + context.Used.Add(currentVertex); + context.Parents.Push(currentVertex); + + var wasPushed = false; + //Pushing children to the stack of vertices to visit. + for (int i = context.Graph[currentVertex].Count - 1; i >=0 ; i--) + { + var nextAdjacent = context.Graph[currentVertex][i]; + if (!context.Used.Contains(nextAdjacent)) + { + wasPushed = true; + stack.Push(nextAdjacent); + context.VertexInfo[nextAdjacent] = (currentVertex, context.TraverseDepth); + } + + } + if (wasPushed) + { + continue; + } + } + + //On exiting the vertex. If graph is not tree, we need to check current parent, to avoid removing vertex if it already was removed, but got visited through another branch. + if (context.Parents.Peek() == currentVertex) + { + context.Parents.Pop(); + exitAction?.Invoke(context); + } + stack.Pop(); + } + } + /// /// Depth-first search with some action on current context diff --git a/DKey.Algorithms/DataStructures/Graph/DepthFirstSearch/DFSTools.cs b/DKey.Algorithms/DataStructures/Graph/DepthFirstSearch/DFSTools.cs new file mode 100644 index 0000000..f4fadd9 --- /dev/null +++ b/DKey.Algorithms/DataStructures/Graph/DepthFirstSearch/DFSTools.cs @@ -0,0 +1,18 @@ +namespace DKey.Algorithms.DataStructures.Graph.DepthFirstSearch; + +public class DFSTools +{ + public List Traverse(DFSContext context, bool reverse = false) + { + var result = new List(); + DFS.Iterative(context, x => + { + result.Add(x.CurrentVertex); + }); + if (reverse) + { + result.Reverse(); + } + return result; + } +} \ No newline at end of file diff --git a/DKey.CodeForces/Program.cs b/DKey.CodeForces/Program.cs index 916b483..38ecabd 100644 --- a/DKey.CodeForces/Program.cs +++ b/DKey.CodeForces/Program.cs @@ -1,11 +1,12 @@ using DKey.Algorithms; -using DKey.CodeForces.Contest2103; +using DKey.CodeForces.Contest2117; +using DKey.CodeForces.Sandbox; namespace DKey.CodeForces; public static class Program { - private static Solver _solver = new Solver2103D(); + private static Solver _solver = new SandboxSolver(); public static void Main() { _solver.Run(); diff --git a/DKey.CodeForces/Sandbox/SandboxSolver.cs b/DKey.CodeForces/Sandbox/SandboxSolver.cs new file mode 100644 index 0000000..d282e0f --- /dev/null +++ b/DKey.CodeForces/Sandbox/SandboxSolver.cs @@ -0,0 +1,43 @@ +using DKey.Algorithms; +using DKey.Algorithms.DataStructures.Graph; +using DKey.Algorithms.DataStructures.Graph.DepthFirstSearch; + +namespace DKey.CodeForces.Sandbox; + +public class SandboxSolver : Solver +{ + public SandboxSolver() : base( new []{typeof(int)}) + { + } + + public override void Solve(object[] objects) + { + var roots = new HashSet(); + var n = (int) objects[0]; + var edges = new List<(int, int)>(); + for (var i = 0; i < n; i++) + { + var parent = IOHelper.ReadInt(); + if (parent == -1) + { + roots.Add(i); + continue; + } + + edges.Add((parent - 1, i)); + } + + var graph = GraphBuilder.Directed(edges, n); + + var maxTraverseDepth = 0; + foreach (var root in roots) + { + var context = new DFSContext(graph.G, root); + DFS.IterativeWithExitAction(context, null, c => + { + maxTraverseDepth = Math.Max(maxTraverseDepth, c.TraverseDepth); + }); + } + output.AddLine(maxTraverseDepth + 1); + } +} \ No newline at end of file diff --git a/DKey.ContestTemplateBuilder/Config.cs b/DKey.ContestTemplateBuilder/Config.cs index bb3518c..5f60222 100644 --- a/DKey.ContestTemplateBuilder/Config.cs +++ b/DKey.ContestTemplateBuilder/Config.cs @@ -3,6 +3,6 @@ public class Config { public static string repoPath = @"C:\Repos\GitHub\DKey.Algorithms\DKey.CodeForces"; - public static string contestID = "2103"; + public static string contestID = "2117"; public static int problemCount = 8; } \ No newline at end of file