True. Each connected component of a forest is a tree. If the component sizes are , their edge counts are , including isolated vertices as size-one components. Summing gives , hence
For a finite connected graph, a spanning tree contains every graph vertex and is connected and acyclic. A minimum spanning tree minimizes over all such trees. A shortest-path tree rooted at is a spanning tree whose unique -to- graph path has length for every graph vertex . Here the weighted path length is the sum of its edge weights. The two optimizations generally differ, as (b) shows. Connectedness is needed for either spanning-tree object to exist.
For the grid, Kruskal's algorithm examines edges in nondecreasing order of weight and accepts an edge exactly when it joins two different components of the current forest. The weights are encountered in the orderThe horizontal and vertical acceptance rules are detailed in the two numbered subanswers. Together they produceThere are horizontal and vertical edges, totaling . Every accepted edge attaches a previously isolated graph vertex to the component already built, so the result is connected and acyclic. The correctness theorem for Kruskal's algorithm, which follows from the minimum spanning tree cut property, proves minimality. Its total cost isFor the tree has one graph vertex, no edges and cost zero. The source's numbered items specify the two edge types; the following subanswers record their contributions to the algorithm.
Kruskal spanning tree of the weighted grid, with accepted horizontal and vertical edges highlighted
. Details. For a connected weighted undirected graph, Kruskal's algorithm begins with each vertex as a separate component and no selected edges. Sort all edges into nondecreasing weight order. Inspect them in that order and add an edge exactly when its endpoints lie in different current components. Merge those components after an addition; stop once edges have been accepted. A disjoint-set data structure implements the component tests and merges.
The accepted edges always form a forest, because an edge whose endpoints were already connected is rejected. To prove optimality, use the invariant that some minimum spanning tree contains every accepted edge. It holds initially. Suppose the next accepted edge is , and let be a minimum spanning tree extending the current forest. If , nothing changes. Otherwise adding to makes a unique graph cycle. The graph path from to in must cross the graph cut between the current component of and the remaining vertices, so that graph cycle contains an edge crossing this graph cut. No accepted edge crosses it. Furthermore : any strictly lighter crossing edge would already have been processed and accepted, since its endpoints could not then have been connected without also being connected now.
Replace by . The resulting spanning tree still contains all previously accepted edges and has cost at most that of , so it too is a minimum spanning tree. This is the exchange argument establishing the invariant. At termination the selected edges themselves form a spanning tree, henceEqual weights cause no difficulty; they may give several optima. On a disconnected graph, processing all edges instead returns a minimum spanning forest. Sorting costs , with near-linear additional cost using an efficient disjoint-set data structure.
Kruskal's algorithm sorts the edges and accepts an edge precisely when it joins two currently different connected components of a graph. A disjoint-set data structure maintains those components:
Kruskal(V, E, w):
A = empty set
make one disjoint set for each vertex in V
for (u,v) in E sorted by nondecreasing w:
if find(u) != find(v):
add (u,v) to A
union(u,v)
if size(A) == size(V) - 1:
break
return AAn accepted edge merges two trees of the current forest. An edge within one component would complete a graph cycle and is skipped. On connected input, after acceptances the forest is a spanning tree. For a one-vertex graph the empty set is already the answer.
In depth-first search, mark every vertex white initially. At a white start vertex , increment a global clock, record and color it gray. Scan its outgoing adjacency list; recursively visit each still-white neighbor, recording the discovery edge. After all neighbors have been processed, color black, increment the clock and record . Start again from every remaining white vertex to obtain a forest. Each vertex is discovered once and each edge scanned once, so the time is with adjacency lists.
The DFS parenthesis property says that for distinct vertices , their intervals and are disjoint or one lies strictly inside the other. Moreover is a proper descendant in a rooted tree of exactly when . A recursive call finishes before its caller returns, while completed calls from separate branches have disjoint intervals; these two possibilities prove the property.
A Haskell representation is:Every tree stores a value at its root, including internal nodes. Interpret the forest by root-left-right preorder traversal, concatenating the results in forest order. Valid values have correct cached sizes, perfect binary trees, nondecreasing sizes and only the permitted initial duplicate. The raw constructors can express invalid representations, so the operations below assume valid values and should form the public interface. Sizes are assumed to fit in
import Prelude hiding (null, head, tail)
data RTree a = Leaf a | Node a (RTree a) (RTree a)
newtype List a = List [(Int, RTree a)]Int; the stated time complexities use constant-time size arithmetic.The first tree's root is the first element. Deleting that root either discards a singleton or exposes two equal-sized child trees:For a node of size , both children have size . Their order agrees with the old preorder traversal, and they become the sole permitted initial duplicate. The rest of the forest was no smaller than the old root tree. Thus both operations preserve the representation invariant and take worst-case time on a nonempty skew-binary random-access list.
head :: List a -> a
head (List ((_,Leaf x):_)) = x
head (List ((_,Node x _ _):_)) = x
head (List []) = error "head: empty list"
tail :: List a -> List a
tail (List ((_,Leaf _):ts)) = List ts
tail (List ((w,Node _ l r):ts)) =
let h = w `div` 2 in List ((h,l):(h,r):ts)
tail (List []) = error "tail: empty list"Skip whole trees using their cached sizes, then descend through one tree:After skipping a size- tree, the desired index decreases by . Inside a node, position zero is the root, positions belong to the left child and the following positions to the right child. This proves correctness by structural induction on the search.
index :: List a -> Int -> a
index (List ts) i
| i < 0 = error "index: negative index"
| otherwise = seek ts i
where
seek [] _ = error "index: out of bounds"
seek ((w,t):us) j
| j < w = at w t j
| otherwise = seek us (j-w)
at _ (Leaf x) 0 = x
at w (Node x l r) j
| j == 0 = x
| j <= h = at h l (j-1)
| otherwise = at h r (j-1-h)
where h = w `div` 2
at _ _ _ = error "index: invalid representation"There are at most forest entries by the supplied bound, and each tree has logarithmic height. Consequently a valid query takes time, with logarithmic worst cases. On a conventional linked list,
xs !! i follows links and costs , hence in the worst case. The first element remains a constant time query in either representation.To find a minimum-weight acyclic subgraph, filter to the subgraph containing only strictly negative-weight edges, and run Kruskal's algorithm on those edges, accepting an edge exactly when it joins different current components. Return the resulting forest, with any omitted vertices regarded as isolated. Zero-weight edges may be omitted without worsening the objective.
To prove correctness, first remove all nonnegative edges from any feasible acyclic graph; removing them preserves acyclicity and cannot increase weight. Thus an optimum using only negative edges exists. Inside a connected component of , any forest not yet connected can be extended by a negative crossing edge: some such edge exists because the original component is connected. Adding it preserves acyclicity and strictly reduces total weight. Consequently an optimum must span each component of , and its restriction there must be a minimum spanning tree. Kruskal's algorithm finds exactly the resulting minimum spanning forest of . This proves optimality among all acyclic subgraphs, including disconnected ones.
Skew-binary random-access list 2026-10-25
Represent a finite list by a forest of value-bearing perfect binary trees of sizes , in nondecreasing order, using the greedy largest sizes and allowing a repeated size only in the first two positions. Concatenated preorder traversals recover the list. Cached tree sizes guide indexing.
Front insertion merges the first two equal-size trees beneath a new root, or adds a singleton if they differ. Removing the first root either discards a singleton or splits its two children into the initial equal-size pair. Both operations inspect and allocate only a bounded number of constructors, taking worst-case constant time and sharing the remaining representation. A positional query skips whole cached tree sizes and then descends through one tree, taking time. Conversion in either direction takes linear time on finite input.
The duplicate-size restriction follows directly from greediness. If two size- trees had any preceding nonempty portion, there would be at least elements available, enough for the next larger perfect binary tree. Three equal-size trees would likewise suffice for that larger tree. Both contradict the greedy representation.
Star forest 2026-10-25
A forest whose connected components of a graph are star graphs. In an inclusion-minimal edge cover, every edge has at least one endpoint of vertex degree one, forcing this structure with no isolated vertex.
Transfer-current theorem 2026-09-28
For oriented edges , the probability that their unoriented versions all belong to a uniform spanning tree is the determinant of the matrix of transfer currents between them. In particular, every finite forest that can be extended to a spanning tree has positive inclusion probability.
