Use dynamic programming in increasing order of the maximum permitted part and then of the remaining sum. Let Count be a sufficiently wide integer type and let table have dimensions (MaxN+1) by (MaxN+1):
PROCEDURE CountPartitions(n: INTEGER): Count;
VAR i, j: INTEGER;
    table: ARRAY MaxN+1, MaxN+1 OF Count;
BEGIN
  table[0,0] := 1; j := 1;
  WHILE j <= n DO table[0,j] := 0; j := j+1 END;
  i := 1;
  WHILE i <= n DO
    table[i,0] := 1; j := 1;
    WHILE j <= n DO
      table[i,j] := table[i-1,j];
      IF j >= i THEN
        table[i,j] := table[i,j] + table[i,j-i]
      END;
      j := j+1
    END;
    i := i+1
  END;
  RETURN table[n,n]
END CountPartitions;
Require . The outer loop invariant says all rows below equal . The inner loop invariant additionally says entries before column in the current row are correct. Its dependencies are the previous row and the earlier column , so no future entry is read. Each state is evaluated once, giving arithmetic operations and stored counts. A memoization table around part (a)'s recursion is another valid way to share states; its entries need a separate “computed” flag because zero is a legitimate answer. Growing count sizes affect bit complexity and can cause integer overflow in a fixed-width Count.
Write parts in nonincreasing order. The array part stores the current prefix, and Emit(i,r,len) completes it using parts at most with remaining sum . With Out as the Oberon output module:
VAR part: ARRAY MaxParts OF INTEGER;

PROCEDURE Emit(i, r, len: INTEGER);
VAR j: INTEGER;
BEGIN
  IF r = 0 THEN
    j := 0;
    WHILE j < len DO
      IF j > 0 THEN Out.Char("+") END;
      Out.Int(part[j], 0); j := j+1
    END;
    Out.Ln
  ELSIF i > 0 THEN
    IF i <= r THEN
      part[len] := i;
      Emit(i, r-i, len+1)
    END;
    Emit(i-1, r, len)
  END
END Emit;

PROCEDURE PrintPartitions(n: INTEGER);
BEGIN
  Emit(n, n, 0)
END PrintPartitions;
The recursion invariant is that part[0..len) is nonincreasing, has sum , and every further part must be at most and at most the last existing part. The first branch includes the next part ; the second excludes it. These alternatives partition all completions, so each integer partition is printed exactly once. A recursive call reduces ; the printing loop's loop invariant is that the first entries have been printed with exactly the necessary separators.
For , no partition has more than parts, and the all-ones partition has exactly . Thus the fixed array requires to handle every partition. When a write occurs, and therefore len < n, so this bound prevents an out-of-range write. Zero prints one empty line, representing the empty integer partition. Available call stack space imposes a further practical limit.
For partitions into distinct parts, using a part prevents using it again. Hence
when , with , for , and for . When , use . Thus change the second call in the final branch of P to D(i-1, n-i) and rename all calls to D. The same split into two disjoint classes proves correctness; its second class removes its unique largest allowed part. The answer is , giving , from and .
Separate integer partitions according to whether they contain a part equal to . Removing one such part is a bijection to partitions of whose parts are at most . The alternatives are disjoint, giving
Use , because the empty integer partition is counted once, and for , with for . This Oberon implementation avoids negative recursive arguments:
PROCEDURE P(i, n: INTEGER): INTEGER;
VAR answer: INTEGER;
BEGIN
  IF n = 0 THEN answer := 1
  ELSIF i = 0 THEN answer := 0
  ELSIF i > n THEN answer := P(i-1, n)
  ELSE answer := P(i-1, n) + P(i, n-i)
  END;
  RETURN answer
END P;

PROCEDURE Partitions(n: INTEGER): INTEGER;
BEGIN
  RETURN P(n, n)
END Partitions;
The precondition is . Each recursive call reduces , proving algorithm termination. Every positive part of a partition of is at most , so the required one-argument count is . Counts require a sufficiently wide integer representation.
Let be the maximum positive machine integer. A positive product suffers integer overflow when . The vulnerable expressions are p*b in part (b), b2[top]*b2[top] in the table guard, and p*b2[k] in the descending search. Even a rejected candidate must be evaluated before its comparison with .
The table guard becomes dangerous as soon as its current entry exceeds : approximately for signed 32-bit integers, or for signed 64-bit integers. These are thresholds for the intermediate power, not for alone. For example, with 32-bit arithmetic, and reach the stored power and then try its overflowing square . If , even the initial square may overflow for a tiny . In part (b), the final test can overflow when the next power above exceeds ; at , this already happens for .
For positive operands, integer division gives the exact equivalence . Therefore replace the three guards respectively by
p <= n DIV b
b2[top] <= n DIV b2[top]
p <= n DIV b2[k]
and perform each multiplication only after its guard succeeds. Every accepted product is then at most . With these guarded products and sufficient table capacity, the algorithms work throughout , . The stored exponents and weights also fit in those machine ranges. Checking for overflow after multiplying would be too late.
Store a second array weight with weight[k] = 2^k. Descending through the binary digits of the answer gives this greedy algorithm:
PROCEDURE FastLog(b, n: INTEGER): INTEGER;
VAR b2, weight: ARRAY enough OF INTEGER;
    top, k, i, p: INTEGER;
BEGIN
  b2[0] := b; weight[0] := 1; top := 0;
  WHILE b2[top]*b2[top] <= n DO
    b2[top+1] := b2[top]*b2[top];
    weight[top+1] := weight[top]+weight[top];
    top := top+1
  END;
  i := 0; p := 1; k := top;
  WHILE k >= 0 DO
    IF p*b2[k] <= n THEN
      p := p*b2[k]; i := i+weight[k]
    END;
    k := k-1
  END;
  RETURN i
END FastLog;
For the second loop, write . Immediately before processing , its loop invariant is
Initially the failed squaring guard gives ; this also holds when , since then . The test succeeds exactly when . If successful, adding selects that binary digit; otherwise the upper bound tightens to . Either way the invariant holds for the next smaller . At , , so i = L.
There are squarings and descending tests. For fixed , this is arithmetic operations, hence logarithmic in the bit length of , and also within the weaker bound. This counts arithmetic operations on integers as unit cost; bit complexity would also charge for the growing operands. No division is used.
Use repeated squaring, including index zero:
b2[0] := b; top := 0;
WHILE b2[top]*b2[top] <= n DO
  b2[top+1] := b2[top]*b2[top];
  top := top+1
END;
The loop invariant is for , with for every stored entry except possibly the initial entry when . Squaring gives , proving preservation. The first failed guard identifies the first larger power outside the range. If , no power with needs storing.
Index zero is deliberately included. The original paper asks for indices but then claims that their products represent every allowable power. Taken without , that claim fails for odd exponents, since every available exponent would be even. The extra initialized entry makes the intended binary expansion argument valid without changing the requested entries.
Let be the largest representable positive integer. The worst case is , requiring indices through . Thus enough = 5 for signed 32-bit integers, or 6 for signed 64-bit integers, suffices for stored powers that fit; a larger convenient constant is harmless. This counts slots starting at zero and does not reserve a slot for an out-of-range sentinel. The multiplication in the guard can still suffer integer overflow, independently of this array capacity bound.
Keep both the exponent and its power. This Oberon procedure uses only the permitted arithmetic:
PROCEDURE IntLog(b, n: INTEGER): INTEGER;
VAR i, p: INTEGER;
BEGIN
  i := 0; p := 1;
  WHILE p*b <= n DO
    p := p*b; i := i+1
  END;
  RETURN i
END IntLog;
The loop invariant is and . It holds initially because . A successful guard permits the next power, and the two assignments preserve the relation between and . At exit, , which is exactly part (a). Each iteration increases , and only finitely many powers of are at most , proving algorithm termination. The returned value is . Its running time is arithmetic operations; integer overflow is deferred to part (e).
Because , exponentiation to base is strictly increasing. The definition of the floor function gives , so the equivalent characterization of the integer logarithm is
Here is a nonnegative integer; gives .
Sort once by nondecreasing end time, then retain the most recent meeting:
Meetings(intervals):
    sort intervals by nondecreasing end
    result = []
    haveMeeting = false
    for (s,e) in intervals:
        if not haveMeeting or s > lastMeeting:
            lastMeeting = e
            append e to result
            haveMeeting = true
    return result
When an interval is inspected, because of the sorted end order. Therefore the interval is already covered exactly when ; otherwise it is the earliest-ending uncovered interval and the algorithm chooses its end. This proves that the scan implements greedy strategy 2. The strict test s > lastMeeting correctly treats equality as covered for closed intervals.
The sorting costs comparisons, and the scan costs , with space for the output and constant scan state. Including an empty input, the overall bound is time, conventionally for . Additional sorting space depends on the selected sorting algorithm. Part (d) proves that the returned number of meetings is minimum.
Let be an interval whose earliest end triggers greedy meeting . After that meeting, every remaining interval starts strictly after : its end is at least , and otherwise it would contain and be removed. Hence
The witness intervals are therefore pairwise disjoint. Every feasible schedule needs a distinct meeting in each one, yielding a lower bound of . The greedy schedule uses exactly meetings and covers everyone, so it is optimal. This is an optimality certificate for the interval stabbing problem.
To follow the source's suggested contradiction explicitly, suppose a schedule with covered everyone. Since ends at , some , so . If and , then none of the first alternative meetings can hit , which starts after . A later meeting must hit it by its end , implying . Mathematical induction gives for . But starts after , later than every alternative meeting. It is uncovered, a contradiction. For a nonempty family is immediately uncovered. The source's hint starts at index zero without defining ; the proof above starts at the actual first meetings instead.
The earliest end is , so strategy 2 first meets at , removing and . Among the remaining intervals the earliest end is , so it next meets at , removing and . This is the two-meeting optimum proved in part (b). The closed endpoints are essential: attendance at exactly an interval's endpoint is permitted.
Four closed intervals suffice:
No time belongs to three intervals, so the maximum number of attendees at one meeting is two. Strategy 1 is allowed to choose , which meets and . The remaining intervals and are disjoint, requiring two further meetings. This run therefore uses three meetings.
However, times and meet everyone: and . One meeting is impossible because . Thus the optimum is two, while strategy 1 can use three. The counterexample deliberately uses an allowed tie between maximum-attendance choices: the instruction to pick “any” such time would require every tie choice to be safe.
Figure 1.
Four availability intervals: a permitted maximum-attendance choice at 2.5 leaves two extra meetings, while the endpoints 1 and 4 suffice
. Details.
A greedy algorithm commits to a locally best available choice and then continues on the remaining problem without revising earlier choices. Correctness requires proving that such choices can belong to an optimal solution; local attractiveness alone is insufficient.
Kruskal's algorithm processes the edges of an undirected weighted graph in nondecreasing weight order. It accepts the next edge exactly when its endpoints lie in different components of the currently chosen forest, thereby preserving the absence of a cycle. This is greedy because it always chooses a cheapest available edge compatible with the forest constraint and never retracts an accepted edge.
The Kruskal safe edge argument explains why the choice works: if a minimum spanning tree extending the current forest lacks the chosen edge, adding that edge creates a cycle; an edge on that cycle crossing the same component boundary can be removed without decreasing connectivity. Such a crossing edge cannot be lighter than the chosen eligible edge, so the exchange does not increase total weight. The new minimum spanning tree includes the greedy choice. For a disconnected graph the same construction yields a minimum spanning forest rather than a single spanning tree.
Use an indexed priority queue of unsettled vertices, keyed by their tentative distances. Initialize the source to zero and other keys to . Each ExtractMin settles the currently closest vertex. Scan its outgoing edges; whenever edge relaxation improves a neighbour's tentative distance, update that neighbour with DecreaseKey. Already settled vertices need no further update, by the correctness of Dijkstra's algorithm for nonnegative weights.
There are at most extractions and at most successful decreases. The indexed priority queue maintains each vertex's current array position and updates this index table on every swap, so locating a key for DecreaseKey costs . Preallocate capacity . Repeated insertion costs , or bottom-up heap construction initializes the queue in time. Scanning adjacency lists costs in total.
For and , the heap-operation contributions are therefore
and the overall bound is
A uniform bound including larger arity and tiny graphs is . Arity greater than the number of vertices offers no useful extra heap levels. These bounds assume adjacency lists; with an adjacency matrix, scanning neighbours contributes instead. No rebuilding of the heap is required after each decrease.
Dijkstra's algorithm solves the single-source shortest path problem in a finite weighted graph with nonnegative edge weights. Given a source , it computes for every vertex the minimum sum of edge weights on a path from to , reporting if is unreachable. Keeping a shortest-path predecessor also recovers the corresponding paths. Directed graphs are allowed; an undirected graph can be represented by two oppositely directed edges. Negative edge weights are outside the algorithm's standard correctness assumptions, while zero weights are allowed.
A decreased key can violate heap order only against its parent. An inserted entry begins at the next free position and uses the same repair:
DecreaseKey(A,i,key):
    if i < 0 or i >= A.heap_size:
        error "invalid index"
    if key > A[i]:
        error "key increased"
    A[i] = key
    while i > 0:
        p = Parent(i)
        if A[p] <= A[i]:
            return
        swap A[p], A[i]
        i = p

Insert(A,key):
    ensure capacity for A.heap_size+1 entries
    i = A.heap_size
    A.heap_size = A.heap_size+1
    A[i] = +infinity
    DecreaseKey(A,i,key)
Here is a sentinel at least as large as every permitted key. One can equivalently write key directly into the new entry and run the upward loop, avoiding any sentinel representation.
At every upward swap, the smaller key moves above its larger parent; the displaced parent remains no larger than the entries below it, as follows from the old heap order. Thus only the new parent edge can be invalid. At most one parent comparison is needed per level, with no scan of siblings. Both operations take time in the usual range, or uniformly including tiny heaps and large .
The heap-operation bound assumes space for the inserted entry. A capacity expansion in a dynamic array can cost for that individual insertion; sufficient preallocation avoids it, while geometric capacity growth adds only constant amortized allocation cost per insertion.
Save the root, move the last active entry to the root, shrink the active prefix, then restore heap order by heapify down:
ExtractMin(A):
    if A.heap_size == 0:
        error "empty heap"
    answer = A[0]
    A[0] = A[A.heap_size-1]
    A.heap_size = A.heap_size-1
    if A.heap_size > 0:
        SiftDown(A,0)
    return answer

SiftDown(A,i):
    while true:
        best = i
        for j = 0,...,d-1:
            c = Child(i,j)
            if c >= A.heap_size:
                break
            if A[c] < A[best]:
                best = c
        if best == i:
            return
        swap A[i], A[best]
        i = best
Only edges descending from the moved entry can violate heap order. If the entry is no larger than every child, the entire heap is valid. Otherwise swapping with a minimum child restores the order at the old position: that child is no larger than the old entry or any sibling. Its original subtree was already ordered, so only the moved entry's new outgoing edges can remain invalid. This is the loop invariant of SiftDown. Each swap moves it down one level, proving termination and correctness.
For , the height is , and selecting a minimum child costs at most comparisons per level. Thus ExtractMin takes time, with auxiliary storage. Empty and singleton heaps take constant time. For , there is at most one nonroot level and the loop examines at most actual children, taking ; this also lies within for . The coarser uniform expression safely includes all small sizes.
The active prefix of the array must represent a complete -ary tree, filled in the prescribed order, and must obey heap order:
Equivalently, every parent is no larger than each existing child. Repeatedly following parents shows that the root contains a global minimum. The array representation already provides the complete-tree shape; it is not enough to check only that the root is a minimum, since the inequality must hold throughout the d-ary min-heap. Assume integral throughout the heap operations.
Compute any topological sort using a standard algorithm, then check its consecutive entries in the adjacency matrix:
DAGHamiltonianPath(A):
    order = TopologicalSort(A)
    for j = 1,...,n-1:
        if not A[order[j],order[j+1]]:
            return "no Hamiltonian path"
    return order
If all checks pass, the returned ordering is a Hamiltonian path. If a check fails but a Hamiltonian path existed, part (d) would force the computed topological sort to equal the unique path order, whose consecutive edges all exist. This contradiction proves the negative answer correct.
A standard topological sort scans all matrix rows and therefore takes time with this input representation; the subsequent edge checks take . The answer is consequently time, with auxiliary storage beyond the input matrix. An bound for an adjacency list must not be substituted for the stipulated adjacency matrix bound.

Pinned article: Introduction to the OurBigBook Project

Welcome to the OurBigBook Project! Our goal is to create the perfect publishing platform for STEM subjects, and get university-level students to write the best free STEM tutorials ever.
Everyone is welcome to create an account and play with the site: ourbigbook.com/go/register. We belive that students themselves can write amazing tutorials, but teachers are welcome too. You can write about anything you want, it doesn't have to be STEM or even educational. Silly test content is very welcome and you won't be penalized in any way. Just keep it legal!
We have two killer features:
  1. topics: topics group articles by different users with the same title, e.g. here is the topic for the "Fundamental Theorem of Calculus" ourbigbook.com/go/topic/fundamental-theorem-of-calculus
    Articles of different users are sorted by upvote within each article page. This feature is a bit like:
    • a Wikipedia where each user can have their own version of each article
    • a Q&A website like Stack Overflow, where multiple people can give their views on a given topic, and the best ones are sorted by upvote. Except you don't need to wait for someone to ask first, and any topic goes, no matter how narrow or broad
    This feature makes it possible for readers to find better explanations of any topic created by other writers. And it allows writers to create an explanation in a place that readers might actually find it.
    Figure 1.
    Screenshot of the "Derivative" topic page
    . View it live at: ourbigbook.com/go/topic/derivative
  2. local editing: you can store all your personal knowledge base content locally in a plaintext markup format that can be edited locally and published either:
    This way you can be sure that even if OurBigBook.com were to go down one day (which we have no plans to do as it is quite cheap to host!), your content will still be perfectly readable as a static site.
    Figure 5. . You can also edit articles on the Web editor without installing anything locally.
    Video 3.
    Edit locally and publish demo
    . Source. This shows editing OurBigBook Markup and publishing it using the Visual Studio Code extension.
  3. https://raw.githubusercontent.com/ourbigbook/ourbigbook-media/master/feature/x/hilbert-space-arrow.png
  4. Infinitely deep tables of contents:
    Figure 6.
    Dynamic article tree with infinitely deep table of contents
    .
    Descendant pages can also show up as toplevel e.g.: ourbigbook.com/cirosantilli/chordate-subclade
All our software is open source and hosted at: github.com/ourbigbook/ourbigbook
Further documentation can be found at: docs.ourbigbook.com
Feel free to reach our to us for any help or suggestions: docs.ourbigbook.com/#contact