|
| 1 | +program DepthFirstSearch; |
| 2 | + |
| 3 | +{$mode objfpc}{$H+} |
| 4 | + |
| 5 | +uses |
| 6 | + Classes, |
| 7 | + Generics.Collections, |
| 8 | + Sysutils; |
| 9 | + |
| 10 | +type |
| 11 | + TIntegerList = specialize TList<integer>; |
| 12 | + TIntegerSet = specialize THashSet<integer>; |
| 13 | + TIntegerStack = specialize TStack<integer>; |
| 14 | + |
| 15 | + TNode = class |
| 16 | + private |
| 17 | + FChildSet: TIntegerSet; |
| 18 | + public |
| 19 | + Id: integer; |
| 20 | + Children: TIntegerList; |
| 21 | + constructor Create(AId: integer); |
| 22 | + destructor Destroy; override; |
| 23 | + procedure AddChild(ChildId: integer); |
| 24 | + end; |
| 25 | + |
| 26 | + TNodeDictionary = specialize TDictionary<integer, TNode>; |
| 27 | + |
| 28 | + { TTree } |
| 29 | + |
| 30 | + TTree = class |
| 31 | + private |
| 32 | + function ContainsNode(NodeId: integer): boolean; |
| 33 | + public |
| 34 | + RootId: integer; |
| 35 | + Nodes: TNodeDictionary; |
| 36 | + constructor Create(ARootId: integer); |
| 37 | + destructor Destroy; override; |
| 38 | + procedure AddNode(Node: TNode); |
| 39 | + function GetNode(NodeId: integer): TNode; |
| 40 | + end; |
| 41 | + |
| 42 | +procedure ShowUsage; |
| 43 | +begin |
| 44 | + Writeln('Usage: please provide a tree in an adjacency matrix form ("0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0") together with a list of vertex values ("1, 3, 5, 2, 4") and the integer to find ("4")'); |
| 45 | + Halt(1); |
| 46 | +end; |
| 47 | + |
| 48 | +{ TNode } |
| 49 | + |
| 50 | +constructor TNode.Create(AId: integer); |
| 51 | +begin |
| 52 | + Id := AId; |
| 53 | + Children := TIntegerList.Create; |
| 54 | + FChildSet := TIntegerSet.Create; |
| 55 | +end; |
| 56 | + |
| 57 | +destructor TNode.Destroy; |
| 58 | +begin |
| 59 | + Children.Free; |
| 60 | + FChildSet.Free; |
| 61 | + inherited; |
| 62 | +end; |
| 63 | + |
| 64 | +procedure TNode.AddChild(ChildId: integer); inline; |
| 65 | +begin |
| 66 | + if FChildSet.Add(ChildId) then |
| 67 | + Children.Add(ChildId); |
| 68 | +end; |
| 69 | + |
| 70 | +{ TTree } |
| 71 | + |
| 72 | +constructor TTree.Create(ARootId: integer); |
| 73 | +begin |
| 74 | + RootId := ARootId; |
| 75 | + Nodes := TNodeDictionary.Create; |
| 76 | +end; |
| 77 | + |
| 78 | +destructor TTree.Destroy; |
| 79 | +var |
| 80 | + Node: TNode; |
| 81 | +begin |
| 82 | + for Node in Nodes.Values do |
| 83 | + Node.Free; |
| 84 | + Nodes.Free; |
| 85 | + inherited; |
| 86 | +end; |
| 87 | + |
| 88 | +procedure TTree.AddNode(Node: TNode); inline; |
| 89 | +begin |
| 90 | + Nodes.AddOrSetValue(Node.Id, Node); |
| 91 | +end; |
| 92 | + |
| 93 | +// Retrieves a node by ID, or returns nil if not found |
| 94 | +function TTree.GetNode(NodeId: integer): TNode; inline; |
| 95 | +begin |
| 96 | + if not Nodes.TryGetValue(NodeId, Result) then |
| 97 | + Result := nil; |
| 98 | +end; |
| 99 | + |
| 100 | +function TTree.ContainsNode(NodeId: integer): boolean; inline; |
| 101 | +begin |
| 102 | + Result := Nodes.ContainsKey(NodeId); |
| 103 | +end; |
| 104 | + |
| 105 | +function ParseIntegerList(const S: string): TIntegerList; |
| 106 | +var |
| 107 | + Parts: TStringArray; |
| 108 | + Part: string; |
| 109 | + Value: integer; |
| 110 | +begin |
| 111 | + if S.Trim.IsEmpty then |
| 112 | + ShowUsage; |
| 113 | + |
| 114 | + Parts := S.Split([',']); |
| 115 | + Result := TIntegerList.Create; |
| 116 | + try |
| 117 | + for Part in Parts do |
| 118 | + begin |
| 119 | + if not TryStrToInt(Trim(Part), Value) then |
| 120 | + begin |
| 121 | + Result.Free; |
| 122 | + ShowUsage; |
| 123 | + end; |
| 124 | + Result.Add(Value); |
| 125 | + end; |
| 126 | + |
| 127 | + if Result.Count = 0 then |
| 128 | + begin |
| 129 | + Result.Free; |
| 130 | + ShowUsage; |
| 131 | + end; |
| 132 | + except |
| 133 | + on E: Exception do |
| 134 | + begin |
| 135 | + Result.Free; |
| 136 | + ShowUsage; |
| 137 | + end; |
| 138 | + end; |
| 139 | +end; |
| 140 | + |
| 141 | +// Build tree from adjacency matrix and vertices |
| 142 | +function CreateTree(const AdjMatrix, Vertices: TIntegerList): TTree; |
| 143 | +var |
| 144 | + N, Row, Col, MatrixIndex: integer; |
| 145 | + Node: TNode; |
| 146 | + Vertex, AdjacentVertex: integer; |
| 147 | +begin |
| 148 | + N := Vertices.Count; |
| 149 | + if (N = 0) or (AdjMatrix.Count <> N * N) then |
| 150 | + ShowUsage; |
| 151 | + |
| 152 | + // Create all nodes and add to tree |
| 153 | + Result := TTree.Create(Vertices.First); |
| 154 | + for Row in Vertices do |
| 155 | + Result.AddNode(TNode.Create(Row)); |
| 156 | + |
| 157 | + // Populate children based on adjacency matrix |
| 158 | + MatrixIndex := 0; |
| 159 | + for Row := 0 to N - 1 do |
| 160 | + begin |
| 161 | + Node := Result.GetNode(Vertices[Row]); |
| 162 | + for Col := 0 to N - 1 do |
| 163 | + begin |
| 164 | + if AdjMatrix[MatrixIndex] <> 0 then |
| 165 | + begin |
| 166 | + AdjacentVertex := Vertices[Col]; |
| 167 | + if not Result.ContainsNode(AdjacentVertex) then |
| 168 | + begin |
| 169 | + Result.Free; |
| 170 | + ShowUsage; |
| 171 | + end; |
| 172 | + Node.AddChild(AdjacentVertex); |
| 173 | + end; |
| 174 | + Inc(MatrixIndex); |
| 175 | + end; |
| 176 | + end; |
| 177 | +end; |
| 178 | + |
| 179 | +// Performs depth-first search for the target value. |
| 180 | +// This uses the iterative version with a TStack for performance. |
| 181 | +function DepthFirstSearch(Tree: TTree; Target: integer): boolean; |
| 182 | +var |
| 183 | + Stack: TIntegerStack; |
| 184 | + Visited: TIntegerSet; |
| 185 | + CurrentId: integer; |
| 186 | + CurrentNode: TNode; |
| 187 | + ChildId: integer; |
| 188 | +begin |
| 189 | + Result := False; |
| 190 | + if Tree = nil then Exit; |
| 191 | + |
| 192 | + Stack := TIntegerStack.Create; |
| 193 | + Visited := TIntegerSet.Create; |
| 194 | + try |
| 195 | + Stack.Capacity := Tree.Nodes.Count; |
| 196 | + Visited.Capacity := Tree.Nodes.Count; |
| 197 | + |
| 198 | + Stack.Push(Tree.RootId); |
| 199 | + |
| 200 | + while Stack.Count > 0 do |
| 201 | + begin |
| 202 | + CurrentId := Stack.Pop; |
| 203 | + |
| 204 | + if not Visited.Add(CurrentId) then |
| 205 | + Continue; |
| 206 | + |
| 207 | + if CurrentId = Target then |
| 208 | + Exit(True); |
| 209 | + |
| 210 | + CurrentNode := Tree.GetNode(CurrentId); |
| 211 | + if CurrentNode <> nil then |
| 212 | + for ChildId in CurrentNode.Children do |
| 213 | + Stack.Push(ChildId); |
| 214 | + end; |
| 215 | + finally |
| 216 | + Stack.Free; |
| 217 | + Visited.Free; |
| 218 | + end; |
| 219 | +end; |
| 220 | + |
| 221 | +var |
| 222 | + AdjMatrix, Vertices: TIntegerList; |
| 223 | + Target: integer; |
| 224 | + Tree: TTree; |
| 225 | +begin |
| 226 | + if ParamCount <> 3 then |
| 227 | + ShowUsage; |
| 228 | + |
| 229 | + AdjMatrix := ParseIntegerList(ParamStr(1)); |
| 230 | + Vertices := ParseIntegerList(ParamStr(2)); |
| 231 | + if not TryStrToInt(ParamStr(3), Target) then |
| 232 | + ShowUsage; |
| 233 | + |
| 234 | + Tree := CreateTree(AdjMatrix, Vertices); |
| 235 | + try |
| 236 | + Writeln(BoolToStr(DepthFirstSearch(Tree, Target), 'true', 'false')); |
| 237 | + finally |
| 238 | + AdjMatrix.Free; |
| 239 | + Vertices.Free; |
| 240 | + Tree.Free; |
| 241 | + end; |
| 242 | +end. |
0 commit comments