brain
tamnd's digital brain — notes, problems, research
41806 notes
Minimum spanning tree code often fails for reasons that are easy to miss in clean textbook examples.
Given a connected weighted undirected graph, find a spanning tree whose total edge weight is minimum.
Throughout this chapter, we have studied minimum spanning trees from multiple perspectives: * Graph theory * Greedy algorithms * Union-find
A minimum spanning tree gives the cheapest way to connect all vertices.
Offline connectivity works well when edges are fixed, or when all updates can be processed in a convenient order.
By this point, you have seen three major minimum spanning tree algorithms: ```text Kruskal Prim
Minimum spanning tree algorithms repeatedly make local decisions.
Kruskal's algorithm builds a minimum spanning tree by selecting edges globally.
You have a set of objects and pairwise distances between them.
Minimum spanning tree algorithms are easy to state, but their performance depends heavily on representation and data structure choices.
After studying cut properties, union-find, Kruskal, Prim, Borůvka, clustering, network design, and complexity analysis, a practical question remains: > How should MST algorithms actually be implemente...
Many graph algorithms repeatedly ask the same question: > Do these two vertices already belong to the same connected component?
The classical MST algorithms were designed for a single machine processing a graph stored in local memory.
Minimum spanning trees minimize the **total weight** of selected edges.
Minimum spanning tree algorithms are usually described in terms of `V` vertices and `E` edges.
The cut property identifies edges that can safely be added to a minimum spanning tree.
Breadth-first search works because every edge contributes the same cost.
Dijkstra's algorithm finds shortest paths by expanding vertices in order of increasing distance from the source.
Between ordinary BFS and Dijkstra lies an interesting class of shortest-path problems.
One of the most powerful ideas in algorithm design is that many problems that do not look like graph problems can be transformed into shortest-path problems.
Breadth-first search (BFS) is the simplest shortest path algorithm.
Shortest-path algorithms are often chosen by correctness first, then by complexity.
Shortest-path code usually fails in predictable ways.
This chapter introduced a substantial collection of shortest-path algorithms.
Use BFS when every edge has the same cost.
Many shortest-path problems are not given as explicit graph structures.
The shortest-path algorithms studied so far naturally divide into two groups.
Every shortest-path algorithm in this chapter appears different on the surface.
Dijkstra's algorithm depends on a crucial assumption: edge weights must be nonnegative.
In the previous recipe, Bellman-Ford was used to compute shortest paths in graphs that contain negative edge weights.
Most shortest-path algorithms answer a single question: > What is the shortest path from the source to the destination?
The previous recipe used Dijkstra’s algorithm with a binary heap and lazy deletion.
Most shortest-path algorithms compute distances.
Shortest-path implementations are prone to subtle errors.
Negative edge weights complicate shortest-path algorithms.
Most shortest-path problems begin with a single source vertex.
Many shortest-path algorithms begin at the source and gradually expand outward until the target is reached.
Shortest-path algorithms are easy to implement incorrectly.
The algorithms covered so far solve the single-source shortest path problem.
Many shortest-path algorithms are designed to handle arbitrary graphs.
Learning shortest-path algorithms is only the first step.
You need to determine whether a graph contains a cycle.
You need to assign labels, colors, or resources to vertices so that adjacent vertices do not conflict.
You need basic measurements that describe the local and global structure of a graph.
You need to arrange tasks in an order that respects dependencies.
You need to turn a real problem into a graph before choosing an algorithm.
You need to identify independent regions within a graph.
You need to visit every vertex exactly once.
You need to model relationships where connections have different costs.
You need to find vertices whose removal disconnects an undirected graph.
You need to explore a graph in order of increasing distance from a starting vertex.
You need to find edges whose removal disconnects a graph.
You need to model relationships that are naturally symmetric.
You need a graph representation that is simple to construct, compact to store, and efficient for algorithms that process edges directly.
You are given a graph problem and need to quickly identify the correct algorithmic approach.
You need to choose the right in-memory representation for a graph.
You need to traverse every edge in a graph exactly once.
You need to find the cheapest route between vertices.
You need to identify groups of vertices that are mutually reachable.
You need to explore a graph systematically.
You need to connect all vertices in a graph while minimizing total cost.
You need to model relationships that have direction.
You need confidence that a graph algorithm handles real inputs, edge cases, and malformed assumptions correctly.
You need a graph representation that supports efficient traversal, scales to large datasets, and works naturally with algorithms such as depth-first search, breadth-first search, topological sorting,...
You need a graph representation that can answer edge-existence queries quickly.
You need to divide vertices into two groups such that every edge connects vertices from different groups.
All previous tree algorithms in this chapter assume that the tree structure is fixed.
Breadth-first search (BFS) visits a tree level by level.
This chapter has introduced a wide range of tree algorithms and data structures.
Depth-first search (DFS) is the fundamental traversal technique for trees.
Expression trees represent computations as tree structures.
Suppose two computers each store a copy of a large dataset.
Many tree problems ask questions about an entire subtree rather than an individual node.
Tree height measures how far a tree extends downward from a node.
Many tree algorithms repeatedly ask the same question: > What is the ancestor of this node k levels above?
Two trees may look different at first glance yet represent exactly the same structure.
Most tree representations focus on speed.
Many tree algorithms eventually become range-query problems.
Most tree algorithms are recursive, not because recursion is elegant, but because trees are recursive objects.
Many tree algorithms compute information relative to a fixed root.
The diameter of a tree is the length of the longest path between any two nodes.
Segment Trees provide efficient range queries and point updates.
A tree in memory is not directly portable.
Not every range-query problem requires the full power of a Segment Tree.
Trees are usually introduced with drawings: circles connected by lines, one circle at the top, several below it, then more below those.
The Lowest Common Ancestor (LCA) of two nodes is the deepest node that is an ancestor of both.
Many search problems involve prefixes.
Most data structures answer questions about the present.
Many tree algorithms process information from a fixed root.
Many tree problems become dramatically easier when you stop thinking of the tree as a tree.
Many tree problems ask questions about paths.
The motion is completely determined by the two lines and the current point.
Represent the airline network by a simple graph $G$ on $2n$ vertices.
We seek all integer triples $(x,y,z)$, none equal to $1$, satisfying
Consider a coat of area $1$ and five patches, each of area at least $\frac{1}{2}$.
Let the trapezoid have bases of lengths $b$ and $a$, with $a<b$.
Begin by examining the three-variable inequality
A strategy can be represented by a decision tree.
Consider small values of $n$ first.
Let the circle have center $O$ and radius $r$.