Dominoes - Competition - algorithm

http://ecoocs.org/contests/ecoo_2007.pdf
I'm studying for the upcoming ecoo regionals for my area and I'm stumped on this one question. I really have no idea where to start.
It is in the "regional" "west and central" section "problem 3 - domino chains".
I keep going over the problem manually and I keep thinking of breadth first search or depth first search, but the dominoes having two sides is seriously throwing my thinking off.
Does anyone have any advice, or maybe some resources that might set me in the right direction?

It looks like this problem calls for a recursive backtracking approach. Keep a 7 by 7 symmetric matrix showing which numbers are attached to which. For example, given tiles 00 12 63 51 you would have the following matrix:
0 1 2 3 4 5 6
-------------
0|1 0 0 0 0 0 0
1|0 0 1 0 0 1 0
2|1 0 0 0 0 0 0
3|0 0 0 0 0 0 1
4|0 0 0 0 0 0 0
5|0 1 0 0 0 0 0
6|0 0 0 1 0 0 0
When you use up a tile by placing it in a potential chain, delete it from the matrix, and put it back in the matrix after you unplace the tile by backtracking. For example, if the chain currecntly contains 51 12, the matrix looks like this:
0 1 2 3 4 5 6
-------------
0|1 0 0 0 0 0 0
1|0 0 0 0 0 0 0
2|0 0 0 0 0 0 0
3|0 0 0 0 0 0 1
4|0 0 0 0 0 0 0
5|0 0 0 0 0 0 0
6|0 0 0 1 0 0 0
Given that the chain currecntly ends in 2, you would look along row 2 for any numbers that can connect to. Not finding any, you would mark down 51 12 as a potential longest chain, and then backtrack to the state where the chain contained only 51.
Maintain a set of all the longest chains you have found, and check a new chain for the existence of itself or its reverse in the set before inserting it.
If you find a longer chain, start a new set. Once you have exhaustively searched through all the possible chains, the size of your set should be the number of variations that are of the longest length.

Personally, when working out these sorts of problems, a great way to solve them is to do them in one case (taking into account that you will increase complexity later) and then increase the complexity. That way you aren't overwhelmed by the complexity and the almost endless "whatifs" that a problem like this can cause.
Also, on the programming competitions I've participated in, 60-70% of the credit was awarded for a solution that got the basic problem correct, and then final percentages were if you handled certain cases correctly. The case that sticks in my mind specifically is we had a mapping problem with a variation of the travelling salesman and if they supplied a graph with a loop, did my solution loop endlessly or did it do something about it.
Thus, with this approach, what I would do is try to solve the problem as directly as possible: take the input as stated by the documentation and just generate the longest chain with the pieces you have. Then increment the complexity by allowing pieces to be rotated etc.
While this is a personal approach to the problem, it has served me well in the past. I hope it serves you well also.

This is a dynamic programming problem, so you can solve it using dynamic programming techniques.
So, if we have these pieces:
45 36 46 56
What is the longest chain that can be made from 4 bones?
Obviously, the longest chain that can be made from 3 bones and 1 more bone.
What is the longest chain that can be made from 3 bones?
Obviously, the longest chain that can be made from 2 bones and 1 more bone.
What is the longest chain that can be made from 2 bones?
Obviously, the longest chain that can be made from 1 bone and 1 more bone.
What is the longest chain that can be made from 1 bone?
Obviously, 1 bone is the longest possible chain.
I think you see by the pattern here, we need to use recursion.
So if we have:
45 36 46 56
Suppose we have a function longest_chain(set_of_pieces). Then we need to check:
longest_chain({36 46 56}) (+ 1 if we can append 45 or 54 else discard this chain)
longest_chain({45 46 56}) (+ 1 if we can append 36 or 63 else discard this chain)
longest_chain({45 36 56}) (+ 1 if we can append 46 or 64 else discard this chain)
longest_chain({45 36 46}) (+ 1 if we can append 56 or 65 else discard this chain)
what is longest_chain({36 46 56})?
longest_chain({46 56}) (+ 1 if we can append 36 or 63 else discard this chain)
longest_chain({36 56}) (+ 1 if we can append 46 or 64 else discard this chain)
longest_chain({36 46}) (+ 1 if we can append 56 or 65 else discard this chain)
what is longest_chain({46 56})?
longest_chain({46}) (+ 1 if we can append 56 or 65 else discard this chain)
longest_chain({56}) (+ 1 if we can append 46 or 64 else discard this chain)
what is longest_chain({46})? Two possibilities: {46} {64}
Can we append 56 or 65 to any of these? Yes, we can make this chain {46, 65} and we discard {64}.
Do the same with longest_chain({56}) and we get: {56, 64}.
Therefore, we now know that longest_chain({46 56}) are {46, 65}, {56, 64}
Continue doing this until you get all answers.
Hope this helps.

Here's how I'd start.
Label the n dominoes D1..Dn.
Let Cm be the set of chains formed using the subset of domines D1..Dm (and C0 = {}).
Cm+1 is formed by trying to insert Dm+1 into all possible places in chains in Cm, plus using Dm+1 where possible to concatenate pairs of disjoint chains from Cm, plus the singleton chain consisting of Dm+1 by itself.
You can probably do some optimisation (e.g., ordering the dominoes), but I'd be inclined to just try this as is before getting too clever.

Related

How to solve 5 * 5 Cube in efficient easy way

There is 5*5 cube puzzle named Happy cube Problem where for given mat , need to make a cube .
http://www.mathematische-basteleien.de/cube_its.htm#top
Its like, 6 blue mats are given-
From the following mats, Need to derive a Cube -
These way it has 3 more solutions.
So like first cub
For such problem, the easiest approach I could imagine was Recursion based where for each cube, I have 6 position , and for each position I will try check all other mate and which fit, I will go again recursively to solve the same. Like finding all permutations of each of the cube and then find which fits the best.So Dynamic Programming approach.
But I am making loads of mistake in recursion , so is there any better easy approach which I can use to solve the same?
I made matrix out of each mat or diagram provided, then I rotated them in each 90 clock-wise 4 times and anticlock wise times . I flip the array and did the same, now for each of the above iteration I will have to repeat the step for other cube, so again recursion .
0 0 1 0 1
1 1 1 1 1
0 1 1 1 0
1 1 1 1 1
0 1 0 1 1
-------------
0 1 0 1 0
1 1 1 1 0
0 1 1 1 1
1 1 1 1 0
1 1 0 1 1
-------------
1 1 0 1 1
0 1 1 1 1
1 1 1 1 0
0 1 1 1 1
0 1 0 1 0
-------------
1 0 1 0 0
1 1 1 1 1
0 1 1 1 0
1 1 1 1 1
1 1 0 1 0
-------------
1st - block is the Diagram
2nd - rotate clock wise
3rd - rotate anti clockwise
4th - flip
Still struggling to sort out the logic .
I can't believe this, but I actually wrote a set of scripts back in 2009 to brute-force solutions to this exact problem, for the simple cube case. I just put the code on Github: https://github.com/niklasb/3d-puzzle
Unfortunately the documentation is in German because that's the only language my team understood, but source code comments are in English. In particular, check out the file puzzle_lib.rb.
The approach is indeed just a straightforward backtracking algorithm, which I think is the way to go. I can't really say it's easy though, as far as I remember the 3-d aspect is a bit challenging. I implemented one optimization: Find all symmetries beforehand and only try each unique orientation of a piece. The idea is that the more characteristic the pieces are, the less options for placing pieces exist, so we can prune early. In the case of many symmetries, there might be lots of possibilities and we want to inspect only the ones that are unique up to symmetry.
Basically the algorithm works as follows: First, assign a fixed order to the sides of the cube, let's number them 0 to 5 for example. Then execute the following algorithm:
def check_slots():
for each edge e:
if slot adjacent to e are filled:
if the 1-0 patterns of the piece edges (excluding the corners)
have XOR != 0:
return false
if the corners are not "consistent":
return false
return true
def backtrack(slot_idx, pieces_left):
if slot_idx == 6:
# finished, we found a solution, output it or whatever
return
for each piece in pieces_left:
for each orientation o of piece:
fill slot slot_idx with piece in orientation o
if check_slots():
backtrack(slot_idx + 1, pieces_left \ {piece})
empty slot slot_idx
The corner consistency is a bit tricky: Either the corner must be filled by exactly one of the adjacent pieces or it must be accessible from a yet unfilled slot, i.e. not cut off by the already assigned pieces.
Of course you can ignore to drop some or all of the consistency checks and only check in the end, seeing as there are only 8^6 * 6! possible configurations overall. If you have more than 6 pieces, it becomes more important to prune early.

Re-sort a vector after a small number of elements have been modified

If we have a vector of size N that was previously sorted, and replace up to M elements with arbitrary values (where M is much smaller than N), is there an easy way to re-sort them at lower cost (i.e. generate a sorting network of reduced depth) than a full sort?
For example if N=10 and M=2 the input might be
10 20 30 40 999 60 70 80 90 -1
Note: the indices of the modified elements are not known (until we compare them with the surrounding elements.)
Here is an example where I know the solution because the input size is small and I was able to find it with a brute-force search:
if N = 5 and M is 1, these would be valid inputs:
0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 1 1 1 0 1 0 0 1 1 1 1 1 1 0
0 0 0 0 1 0 0 1 0 1 0 1 0 0 1 0 1 1 1 1 1 0 1 1 1 1 1 1 1 1
0 0 0 1 0 0 0 1 1 0 0 1 0 1 1 1 0 0 0 0 1 1 0 1 1
0 0 0 1 1 0 0 1 1 1 0 1 1 0 1 1 0 0 0 1 1 1 1 0 1
For example the input may be 0 1 1 0 1 if the previously sorted vector was 0 1 1 1 1 and the 4th element was modified, but there is no way to form 0 1 0 1 0 as a valid input, because it differs in at least 2 elements from any sorted vector.
This would be a valid sorting network for re-sorting these inputs:
>--*---*-----*-------->
| | |
>--*---|-----|-*---*-->
| | | |
>--*---|-*---*-|---*-->
| | | |
>--*---*-|-----*---*-->
| |
>--------*---------*-->
We do not care that this network fails to sort some invalid inputs (e.g. 0 1 0 1 0.)
And this network has depth 4, a saving of 1 compared with the general case (a depth of 5 generally necessary to sort a 5-element vector.)
Unfortunately the brute-force approach is not feasible for larger input sizes.
Is there a known method for constructing a network to re-sort a larger vector?
My N values will be in the order of a few hundred, with M not much more than √N.
Ok, I'm posting this as an answer since the comment restriction on length drives me nuts :)
You should try this out:
implement a simple sequential sort working on local memory (insertion sort or sth. similar). If you don't know how - I can help with that.
have only a single work-item perform the sorting on the chunk of N elements
calculate the maximum size of local memory per work-group (call clGetDeviceInfo with CL_DEVICE_LOCAL_MEM_SIZE) and derive the maximum number of work-items per work-group,
because with this approach your number of work-items will most likely be limited by the amount of local memory.
This will probably work rather well I suspect, because:
a simple sort may be perfectly fine, especially since the array is already sorted to a large degree
parallelizing for such a small number of items is not worth the trouble (using local memory however is!)
since you're processing billions of such small arrays, you will achieve a great occupancy even if only single work-items process such arrays
Let me know if you have problems with my ideas.
EDIT 1:
I just realized I used a technique that may be confusing to others:
My proposal for using local memory is not for synchronization or using multiple work items for a single input vector/array. I simply use it to get a low read/write memory latency. Since we use rather large chunks of memory I fear that using private memory may cause swapping to slow global memory without us realizing it. This also means you have to allocate local memory for each work-item. Each work-item will access its own chunk of local memory and use it for sorting (exclusively).
I'm not sure how good this idea is, but I've read that using too much private memory may cause swapping to global memory and the only way to notice is by looking at the performance (not sure if I'm right about this).
Here is an algorithm which should yield very good sorting networks. Probably not the absolute best network for all input sizes, but hopefully good enough for practical purposes.
store (or have available) pre-computed networks for n < 16
sort the largest 2^k elements with an optimal network. eg: bitonic sort for largest power of 2 less than or equal to n.
for the remaining elements, repeat #2 until m < 16, where m is the number of unsorted elements
use a known optimal network from #1 to sort any remaining elements
merge sort the smallest and second-smallest sub-lists using a merge sorting network
repeat #5 until only one sorted list remains
All of these steps can be done artificially, and the comparisons stored into a master network instead of acting on the data.
It is worth pointing out that the (bitonic) networks from #2 can be run in parallel, and the smaller ones will finish first. This is good, because as they finish, the networks from #5-6 can begin to execute.

generating bitboard masks for move

I'm trying to understand how works bitboard representation in chess programming and I can't find usefull information (or just can't translate it correctly ^^) about one detail. My question is, how to generate automaticly masks for move on every position by every piece. I assume its an matrix where each piece type have define every field he can move from this position (array[5][64] for wP, bP, K, R, N, B). For example for Rook on position below, only allowed positions are:
0 0 1 0 0 0 0 0
0 0 1 0 0 0 0 0
0 0 1 0 0 0 0 0
0 0 1 0 0 0 0 0
1 1 R 1 1 1 1 1
0 0 1 0 0 0 0 0
0 0 1 0 0 0 0 0
0 0 1 0 0 0 0 0
I assume i have to create something like this for each piece type and for every tile it can step but do i have to hardcoded it manually to array or there is some possibility to automatize this process and precompute it after program run?
You could fairly easily precompute all of the bitboards that you need, since the rules of chess are well defined. For example, here is a function (in python) that would compute legal moves for a rook:
import sys
def rook(x, y):
for i in range (1, 9):
for j in range (1, 9):
if x == i or y == j:
sys.stdout.write("1")
else:
sys.stdout.write("0")
sys.stdout.write("\n")
print "Bit board of legal moves for a rook at 1, 3:"
rook(1, 3)
Instead of printing out the bitboard, you would likely store it in a compact format, such as an array of 64 bit values (since an 8x8 board needs 64 bits for each board).
This is a fairly extreme optimization technique, so the details of its implementation are going to get hairy (and be a pain to debug).
I used the wiki bitboard page as reference.

Enumerate graphs under edge and symmetry constraints

I would like to create the set of all directed graphs with n vertices where each vertex has k direct successors and k direct predecessors. n and k won't be that large, rather around n = 8 and k = 3. The set includes cyclic and acyclic graphs. Each graph in turn will serve as a template for sampling a large number of weighted graphs.
My interest is in the role of topology motifs so I don't want to sample weights for any two graphs that are symmetric to each other, where symmetry means that no permutation of vertices exists in one graph that transforms it into the other.
A naive solution would be to consider the 2 ^ (n * (n - 1)) adjacency matrices and eliminate all those (most of them) for which direct successor or predecessor constraints are violated. For n = 8, that's still few enough bits to represent and simply enumerate each matrix comfortably inside a uint64_t.
Keeping track of row counts and column counts would be another improvement, but the real bottleneck will be adding the graph to the result set, at which point we need to test for symmetry against each other graph that's already in the set. For n = 8 that would be already more than 40,000 permutations per insert operation.
Could anyone refer me to an algorithm that I could read up on that can do all this in a smarter way? Is there a graph library for C, C++, Java, or Python that already implements such a comprehensive graph generator? Is there a repository where someone has already "tabulated" all graphs for reasonable n and k?
Graph isomorphism is, in my opinion, not something you should be thinking about implementing yourself. I believe the current state-of-the-art is Brendan McKay's Nauty (and associated programs/libraries). It's a bit of a bear to work with, but it may be worth it to avoid doing your own, naive graph isomorphism. Also, it's primarily geared towards undirected graphs, but it can do digraphs as well. You may want to check out the geng (which generates undirected graphs) and directg (which generates digraphs given an underlying graph) utilities that come with Nauty.
This is more of a comment than an answer, because it seems like I have missed something in your question.
First of all, is it possible for such a graph to be acyclic?
I am also wondering about your symmetry constraint. Does this not make all such graphs symmetric to one another? Is it allowed to permute rows and columns of the connection-matrix?
For example, if we allow self-connections in the graph, does the following connection-matrix fulfill your conditions?
1 1 0 0 0 0 0 1
1 1 1 0 0 0 0 0
0 1 1 1 0 0 0 0
0 0 1 1 1 0 0 0
0 0 0 1 1 1 0 0
0 0 0 0 1 1 1 0
0 0 0 0 0 1 1 1
1 0 0 0 0 0 1 1
Starting from this matrix, is it then not possible to permute the rows and columns of it to obtain all such graphs where all rows and columns have a sum of three?
One example of such a matrix can be obtained from the above matrix A in the following way (using MATLAB).
>> A(randperm(8),randperm(8))
ans =
0 1 0 0 0 1 1 0
0 0 1 0 1 0 1 0
1 1 0 1 0 0 0 0
1 1 0 0 0 1 0 0
1 0 0 1 0 0 0 1
0 0 1 1 0 0 0 1
0 0 1 0 1 0 0 1
0 0 0 0 1 1 1 0
PS. In this case I have repeated the command a few times in order to obtain a matrix with only zeros in the diagonal. :)
Edit
Ah, I see from your comments that I was not correct. Of course the permutation index must be the same for rows and columns. I at least should have noticed it when I started out with a graph with self-connections and obtained one without them after the permutation.
A random isomorphic permutation would instead look like this:
idx = randperm(8);
A(idx,idx);
which will keep all the self-connections.
Perhaps this could be of some use when the matrices are generated, but it is not at all as useful as I thought it would be.

Sorting a binary 2D matrix?

I'm looking for some pointers here as I don't quite know where to start researching this one.
I have a 2D matrix with 0 or 1 in each cell, such as:
1 2 3 4
A 0 1 1 0
B 1 1 1 0
C 0 1 0 0
D 1 1 0 0
And I'd like to sort it so it is as "upper triangular" as possible, like so:
4 3 1 2
B 0 1 1 1
A 0 1 0 1
D 0 0 1 1
C 0 0 0 1
The rows and columns must remain intact, i.e. elements can't be moved individually and can only be swapped "whole".
I understand that there'll probably be pathological cases where a matrix has multiple possible sorted results (i.e. same shape, but differ in the identity of the "original" rows/columns.)
So, can anyone suggest where I might find some starting points for this? An existing library/algorithm would be great, but I'll settle for knowing the name of the problem I'm trying to solve!
I doubt it's a linear algebra problem as such, and maybe there's some kind of image processing technique that's applicable.
Any other ideas aside, my initial guess is just to write a simple insertion sort on the rows, then the columns and iterate that until it stabilises (and hope that detecting the pathological cases isn't too hard.)
More details: Some more information on what I'm trying to do may help clarify. Each row represents a competitor, each column represents a challenge. Each 1 or 0 represents "success" for the competitor on a particular challenge.
By sorting the matrix so all 1s are in the top-right, I hope to then provide a ranking of the intrinsic difficulty of each challenge and a ranking of the competitors (which will take into account the difficulty of the challenges they succeeded at, not just the number of successes.)
Note on accepted answer: I've accepted Simulated Annealing as "the answer" with the caveat that this question doesn't have a right answer. It seems like a good approach, though I haven't actually managed to come up with a scoring function that works for my problem.
An Algorithm based upon simulated annealing can handle this sort of thing without too much trouble. Not great if you have small matrices which most likely hae a fixed solution, but great if your matrices get to be larger and the problem becomes more difficult.
(However, it also fails your desire that insertions can be done incrementally.)
Preliminaries
Devise a performance function that "scores" a matrix - matrices that are closer to your triangleness should get a better score than those that are less triangle-y.
Devise a set of operations that are allowed on the matrix. Your description was a little ambiguous, but if you can swap rows then one op would be SwapRows(a, b). Another could be SwapCols(a, b).
The Annealing loop
I won't give a full exposition here, but the idea is simple. You perform random transformations on the matrix using your operations. You measure how much "better" the matrix is after the operation (using the performance function before and after the operation). Then you decide whether to commit that transformation. You repeat this process a lot.
Deciding whether to commit the transform is the fun part: you need to decide whether to perform that operation or not. Toward the end of the annealing process, you only accept transformations that improved the score of the matrix. But earlier on, in a more chaotic time, you allow transformations that don't improve the score. In the beginning, the algorithm is "hot" and anything goes. Eventually, the algorithm cools and only good transforms are allowed. If you linearly cool the algorithm, then the choice of whether to accept a transformation is:
public bool ShouldAccept(double cost, double temperature, Random random) {
return Math.Exp(-cost / temperature) > random.NextDouble();
}
You should read the excellent information contained in Numerical Recipes for more information on this algorithm.
Long story short, you should learn some of these general purpose algorithms. Doing so will allow you to solve large classes of problems that are hard to solve analytically.
Scoring algorithm
This is probably the trickiest part. You will want to devise a scorer that guides the annealing process toward your goal. The scorer should be a continuous function that results in larger numbers as the matrix approaches the ideal solution.
How do you measure the "ideal solution" - triangleness? Here is a naive and easy scorer: For every point, you know whether it should be 1 or 0. Add +1 to the score if the matrix is right, -1 if it's wrong. Here's some code so I can be explicit (not tested! please review!)
int Score(Matrix m) {
var score = 0;
for (var r = 0; r < m.NumRows; r++) {
for (var c = 0; c < m.NumCols; c++) {
var val = m.At(r, c);
var shouldBe = (c >= r) ? 1 : 0;
if (val == shouldBe) {
score++;
}
else {
score--;
}
}
}
return score;
}
With this scoring algorithm, a random field of 1s and 0s will give a score of 0. An "opposite" triangle will give the most negative score, and the correct solution will give the most positive score. Diffing two scores will give you the cost.
If this scorer doesn't work for you, then you will need to "tune" it until it produces the matrices you want.
This algorithm is based on the premise that tuning this scorer is much simpler than devising the optimal algorithm for sorting the matrix.
I came up with the below algorithm, and it seems to work correctly.
Phase 1: move rows with most 1s up and columns with most 1s right.
First the rows. Sort the rows by counting their 1s. We don't care
if 2 rows have the same number of 1s.
Now the columns. Sort the cols by
counting their 1s. We don't care
if 2 cols have the same number of
1s.
Phase 2: repeat phase 1 but with extra criterions, so that we satisfy the triangular matrix morph.
Criterion for rows: if 2 rows have the same number of 1s, we move up the row that begin with fewer 0s.
Criterion for cols: if 2 cols have the same number of 1s, we move right the col that has fewer 0s at the bottom.
Example:
Phase 1
1 2 3 4 1 2 3 4 4 1 3 2
A 0 1 1 0 B 1 1 1 0 B 0 1 1 1
B 1 1 1 0 - sort rows-> A 0 1 1 0 - sort cols-> A 0 0 1 1
C 0 1 0 0 D 1 1 0 0 D 0 1 0 1
D 1 1 0 0 C 0 1 0 0 C 0 0 0 1
Phase 2
4 1 3 2 4 1 3 2
B 0 1 1 1 B 0 1 1 1
A 0 0 1 1 - sort rows-> D 0 1 0 1 - sort cols-> "completed"
D 0 1 0 1 A 0 0 1 1
C 0 0 0 1 C 0 0 0 1
Edit: it turns out that my algorithm doesn't give proper triangular matrices always.
For example:
Phase 1
1 2 3 4 1 2 3 4
A 1 0 0 0 B 0 1 1 1
B 0 1 1 1 - sort rows-> C 0 0 1 1 - sort cols-> "completed"
C 0 0 1 1 A 1 0 0 0
D 0 0 0 1 D 0 0 0 1
Phase 2
1 2 3 4 1 2 3 4 2 1 3 4
B 0 1 1 1 B 0 1 1 1 B 1 0 1 1
C 0 0 1 1 - sort rows-> C 0 0 1 1 - sort cols-> C 0 0 1 1
A 1 0 0 0 A 1 0 0 0 A 0 1 0 0
D 0 0 0 1 D 0 0 0 1 D 0 0 0 1
(no change)
(*) Perhaps a phase 3 will increase the good results. In that phase we place the rows that start with fewer 0s in the top.
Look for a 1987 paper by Anna Lubiw on "Doubly Lexical Orderings of Matrices".
There is a citation below. The ordering is not identical to what you are looking for, but is pretty close. If nothing else, you should be able to get a pretty good idea from there.
http://dl.acm.org/citation.cfm?id=33385
Here's a starting point:
Convert each row from binary bits into a number
Sort the numbers in descending order.
Then convert each row back to binary.
Basic algorithm:
Determine the row sums and store
values. Determine the column sums
and store values.
Sort the row sums in ascending order. Sort the column
sums in ascending order.
Hopefully, you should have a matrix with as close to an upper-right triangular region as possible.
Treat rows as binary numbers, with the leftmost column as the most significant bit, and sort them in descending order, top to bottom
Treat the columns as binary numbers with the bottommost row as the most significant bit and sort them in ascending order, left to right.
Repeat until you reach a fixed point. Proof that the algorithm terminates left as an excercise for the reader.

Resources