mirror of
git://git.tartarus.org/simon/puzzles.git
synced 2025-04-20 07:31:30 -07:00

Thanks to Amir Livne Bar-on, who implemented this variant from a description posted in the Mastodon thread following up my recent blog post about loop-finding. The revised algorithm has the same asymptotic complexity as the one I already had. But it has better constant factors, and less code: it can run in a single depth-first pass over the graph instead of three separate passes, and it needs to store fewer variables per vertex. This version relies on the insight that if you DFS over an undirected graph and imagine it constructing a rooted spanning forest with each component's tree rooted at whatever vertex you started that component from, then every edge that the DFS visits without making it part of the spanning forest must join a vertex to one of its direct ancestors in that component's tree. (Because the other options are that it joins the DFS's current vertex to one the search hasn't visited at all yet – in which case the DFS _would_ follow it, and make it a forest edge after all. Or else it joins this vertex to a cousin in an earlier finished subtree – but then when the DFS processed that subtree, it would have explored the same edge in the other direction, and added our current vertex to that subtree, which by assumption it didn't.) Hence, instead of assigning every vertex a distinct integer label and calculating the min/max label reachable from each subtree, we can instead assign each vertex its tree depth, and simply calculate the minimum _depth_ of vertex reachable from each subtree: if a subtree starting at depth D can reach a vertex at depth <D, it's because there's one of those non-tree edges to a vertex outside the subtree, so the tree edge entering the subtree isn't a bridge. And since every non-tree edge must point to a vertex we've already seen (and hence assigned a depth to), this can be done in the same pass as calculating the depths in the first place - and we don't even need to _store_ the spanning forest we generate.
This is the README accompanying the source code to Simon Tatham's puzzle collection. The collection's web site is at <https://www.chiark.greenend.org.uk/~sgtatham/puzzles/>. The puzzle collection is built using CMake <https://cmake.org/>. To compile in the simplest way (on any of Linux, Windows or Mac), run these commands in the source directory: cmake . cmake --build . The manual is provided in Windows Help format for the Windows build; in text format for anyone who needs it; and in HTML for the Mac OS X application and for the web site. It is generated from a Halibut source file (puzzles.but), which is the preferred form for modification. To generate the manual in other formats, rebuild it, or learn about Halibut, visit the Halibut website at <https://www.chiark.greenend.org.uk/~sgtatham/halibut/>.
Description
Languages
C
93.3%
JavaScript
1.4%
Objective-C
1.1%
CMake
1.1%
HTML
0.8%
Other
2.2%