Finding the max sum of elements in matrix [duplicate] - c++

Just looking for a bit of direction, I realise that the example given is possible to solve using brute force iteration, but I am looking for a more elegant (ie. mathematical?) solution which could potentially solve significantly larger examples (say 20x20 or 30x30). It is entirely possible that this cannot be done, and I have had very little success in coming up with an approach which does not rely on brute force...
I have a matrix (call it A) which is nxn. I wish to select a subset (call it B) of points from matrix A. The subset will consist of n elements, where one and only one element is taken from each row and from each column of A. The output should provide a solution (B) such that the sum of the elements that make up B is the maximum possible value, given these constraints (eg. 25 in the example below). If multiple instances of B are found (ie. different solutions which give the same maximum sum) the solution for B which has the largest minimum element should be selected.
B could also be a selection matrix which is nxn, but where only the n desired elements are non-zero.
For example:
if A =
|5 4 3 2 1|
|4 3 2 1 5|
|3 2 1 5 4|
|2 1 5 4 3|
|1 5 4 3 2|
=> B would be
|5 5 5 5 5|
However, if A =
|5 4 3|
|4 3 2|
|3 2 1|
B =
|3 3 3|
As the minimum element of B is 3 which is larger than for
|5 3 1|
or
|4 4 1|
which also both sum to 9

Your problem is almost identical to the Assignment problem, which can e.g. be solved by the Hungarian algorithm in polynomial time.
Note that the assignment problem is usually a minimization problem, but multiplying your matrix with -1 and adding some constant should make the method applicable. Further, there is no formal tie-braking condition, for case of multiple optimal solutions. However, the method yields you a solution having the optimal sum. Let m be the minimum summand. Modify your matrix by setting all entries less or equal to m to zero and solve again. Either you get a solution with the same sum that is better than the last one. If not, the previous solution was already optimal.

As Matthias indicated you should use backtracking.
Find a reasonable solution. Select max values from each row and see if they are non-overlapping. If not, then perturb part of the solution so that the result becomes non-overlapping.
Define fitness of a partial solution. Let us say you are picking up value for each row iteratively and you have already picked values from first k rows. The fitness of this solution equals sum of the already picked values + max values from remaining rows and unselected columns
Now recursively start searching for solution. Select the values from first row, calculate their fitness and insert them into a priority queue. Remove all the solutions whose fitness is lower than the current optimal solution (initialized in step 1). Pick the solution at the head of the queue, calculate the next level of solutions and insert them back to the priority queue. Once you have selected values from all columns and rows, calculate the sum, and if it is higher than current optimal, replace it.

Ouch. This algorithm is wrong; there is no proof because it's wrong and therefore it's impossible to prove that it's correct. ;) I'm leaving it here because I'm too attached to delete it entirely, and it's a good demonstration of why you should formally prove algorithms instead of saying "this looks right! There's no possible way this could fail to work!"
I'm giving this solution without proof, for the time being. I have a proof sketch but I'm having trouble proving optimal substructure for this problem. Anyway...
Problem
Given a square array of numbers, select as many "non-overlapping" numbers as possible so that the sum of the selected numbers is maximised. "Non-overlapping" means that no two numbers can be from the same row or the same column.
Algorithm
Let A be a square array of n by n numbers.
Let Aij denote the element of A in the ith row and jth column.
Let S( i1:i2, j1:j2 ) denote the optimal sum of non-overlapping numbers for a square subarray of A containing the intersection of rows i1 to i2 and columns j1 to j2.
Then the optimal sum of non-overlapping numbers is denoted S( 1:n , 1:n ) and is given as follows:
S( 1:n , 1:n ) = max { [ S( 2:n , 2:n ) + A11 ]
[ S( 2:n , 1:n-1 ) + A1n ]
[ S( 1:n-1 , 2:n ) + An1 ]
[ S( 1:n-1 , 1:n-1 ) + Ann ] }
(recursively)
Note that S( i:i, j:j ) is simply Aij.
That is, the optimal sum for a square array of size n can be determined by separately computing the optimal sum for each of the four sub-arrays of size n-1, and then maximising the sum of the sub-array and the element that was "left out".
S for |# # # #|
|# # # #|
|# # # #|
|# # # #|
Is the best of the sums S for:
|# | | #| |# # # | | # # #|
| # # #| |# # # | |# # # | | # # #|
| # # #| |# # # | |# # # | | # # #|
| # # #| |# # # | | #| |# |
Implementation
The recursive algorithm above suggests a recursive solution:
def S(A,i1,i2,j1,j2):
if (i1 == i2) and (j1==j2):
return A[i1][j1]
else:
return max ( S( A, i1+1, i2, j1+1, j2) + A[i1][j1] ],
S( A, i1+1, i2, j1, j2-1) + A[i1][j2] ],
S( A, i1, i2-1, j1+1, j2) + A[i2][j1] ],
S( A, i1, i2-1, j1, j2-1) + A[i2][j2] ], )
Note that this will make O(4^n) calls to S()!! This is much better than the factorial O(n!) time complexity of the "brute force" solution, but still awful performance.
The important thing to note here is that many of the calls are repeated with the same parameters. For example, in solving a 3*3 array, each 2*2 array is solved many times.
This suggests two possible solutions for a speedup:
Make the recursive function S() cache results so that it only needs to S(A,i1,i2,j1,j2) once for each i1,i2,j1,j2. This means that S() only needs to calculate O(n^3) results - all other requests will be fufilled from cache. (This is called memoising.)
Instead of starting at the top, with the large n*n array, and working down through successively smaller subproblems, start at the bottom with the smallest possible subproblems and build up to the n*n case. This is called dynamic programming. This is also O(n^3), but it's a much faster O(n^3) because you don't have to hit a cache all the time.
The dynamic programming solution proceeds somewhat like:
Find optimal solutions to all 1x1 sub-arrays. (Trivial.)
Find optimal solutions for all 2x2 sub-arrays.
Find optimal solutions for all 3x3 sub-arrays.
...
Find optimal solutions for all n-1 * n-1 sub-arrays.
Find optimal solutions for the complete n*n sub-array.
Notes on this solution:
No proof yet. I'm working on it.
You'll note the algorithm above only gives you S(), the optimal sum. It doesn't tell you which numbers actually make up that sum. You get to add in your own method of backtracing your path to the solution.
The algorithm above doesn't guarantee the property that ties like 2,2 vs. 1,3 will be broken in favour of having all the individual numbers be as large as possible (so that 2,2 wins.) I believe you can define max() to break ties in favour of the largest numbers possible, and that will do what you want, but I can't prove it.
General notes:
Dynamic programming is a powerful technique for devising fast algorithms for any problem which exhibits two properties:
Optimal substructure: A problem can be broken down into slightly smaller parts, each of which can be used as part of the solution to the original problem.
Overlapping subproblems means that there are few actual subproblems to solve, and the solutions to the subproblems are re-used many times.
If the problem has optimal substructure, and the problem breaks down into slightly smaller problems - say a problem of size n breaks down into subproblems of size n-1 - then the problem can be solved by dynamic programming.
If you can split the problem into much smaller chunks - say chopping a problem of size n into halves, each of size n/2 - that's divide and conquer, not dynamic programming. Divide and conquer solutions are generally very fast - for example binary search will find an element in a sorted array in O(log n) time.

This is related to the n Queens problem, except that you do not care about the diagonal and you have weighted solutions. As the Queens problem, you can solve it by (multiple) backtracking.
I.e., once you find a solution you remember its weight, mark the soulution as invalid, and start over. The (a) solution with the highest weight wins.

Related

Fetch Words Starting/Containing/Ending With Fragment in a Word Dictionary

Assuming that we have a list of all dictionary words from A-Z from the English dictionary.
I have three cases to perform on these list of words:
1) find out all the words that are "starting with" a particular fragment
eg: If my fragment is 'car', word 'card' should be returned
2) find out all the words that "contains" the fragment as the substring
eg: If my fragment is 'ace', word 'facebook' should be returned
3) find out all the words that are "ending with" a particular fragment
eg: If my fragment is 'age', word 'image' should be returned
After some searching exercise on the internet, I found that 1) can be done through trie/compressed trie and 3) can be done through suffix tree.
I am unsure of how 2) can be achieved.
Plus are there any better scenarios wherein all these three cases can be handled? As maintaining both prefix and suffix tree could be a memory intensive task.
Kindly let me know for any other areas to look out for.
Thanks in advance.
PS: I will be using C++ to achieve this
EDIT 1: For the time being I constructed a suffix tree with immense help from here.
Single Word Suffix Tree Generation in C Language
Here, I need to construct a suffix tree for the entire english dictionary words. So should I create a
a) separate suffix tree for each word OR
b) create a generalized suffix tree for all words.
I am not sure how to track individual trees for each word while substring matching in the a) case
Any pointers?
As I pointed out in a comment, the prefix and suffix cases are covered by the general substring case (#2). All prefixes and suffixes are by definition substrings as well. So all we have to solve is the general substring problem.
Since you have a static dictionary, you can preprocess it relatively easily into a form that is fast to query for substrings. You could do this with a suffix tree, but it's far easier to construct and deal with simple sorted flat vectors of data, so that's what I'll describe here.
The end goal, then, is to have a list of sub-words that are sorted so that a binary search can be done to find a match.
First, observe that in order to find the longest substrings that match the query fragment it is not necessary to list all possible substrings of each word, but merely all possible suffixes; this is because all substrings can be merely thought of as prefixes of suffixes. (Got that? It's a little mind-bending the first time you encounter it, but simple in the end and very useful.)
So, if you generate all the suffixes of each dictionary word, then sort them all, you have enough to find any specific substring in any of the dictionary words: Do a binary search on the suffixes to find the lower bound (std::lower_bound) -- the first suffix that starts with the query fragment. Then find the upper bound (std::upper_bound) -- this will be one past the last suffix that starts with the query fragment. All of the suffixes in the range [lower, upper[ must start with the query fragment, and therefore all of the words that those suffixes originally came from contain the query fragment.
Now, obviously actually spelling out all the suffixes would take an awful lot of memory -- but you don't need to. A suffix can be thought of as merely an index into a word -- the offset at which the suffix begins. So only a single pair of integers is required for each possible suffix: one for the (original) word index, and one for the index of the suffix in that word. (You can pack these two together cleverly depending on the size of your dictionary for even greater space savings.)
To sum up, all you need to do is:
Generate an array of all the word-suffix index pairs for all the words.
Sort these according to their semantic meaning as suffixes (not numerical value). I suggest std::stable_sort with a custom comparator. This is the longest step, but it can be done once, offline since your dictionary is static.
For a given query fragment, find the lower and upper bounds in the sorted suffix indices. Each suffix in this range corresponds to a matching substring (of the length of the query, starting at the suffix index in the word at the word index). Note that some words may match more than once, and that matches may even overlap.
To clarify, here's a minuscule example for a dictionary composed of the words "skunk" and "cheese".
The suffixes for "skunk" are "skunk", "kunk", "unk", "nk", and "k". Expressed as indices, they are 0, 1, 2, 3, 4. The suffixes for "cheese" are "cheese", "heese", "eese", "ese", "se", and "e". The indices are 0, 1, 2, 3, 4, 5.
Since "skunk" is the first word in our very limited imaginary dictionary, we'll assign it index 0. "cheese" is at index 1. So the final suffixes are: 0:0, 0:1, 0:2, 0:3, 0:4, 1:0, 1:1, 1:2, 1:3, 1:4, 1:5.
Sorting these suffixes yields the following suffix dictionary (I added the actual corresponding textual substrings for illustration only):
0 | 0:0 | cheese
1 | 0:5 | e
2 | 0:2 | eese
3 | 0:3 | ese
4 | 0:1 | heese
5 | 1:4 | k
6 | 1:1 | kunk
7 | 1:3 | nk
8 | 0:4 | se
9 | 1:0 | skunk
10 | 1:2 | unk
Consider the query fragment "e". The lower bound is 1, since "e" is the first suffix that is greater than or equal to the query "e". The upper bound is 4, since 4 ("heese") is the first suffix that is greater than "e". So the suffixes at 1, 2, and 3 all start with the query, and therefore the words they came from all contain the query as a substring (at the suffix index, for the length of the query). In this case, all three of these suffixes belong to "cheese", at different offsets.
Note that for a query fragment that's not a substring of any of the words (e.g. "a" in this example), there are no matches; in such a case, the lower and upper bounds will be equal.
You can try aho corasick algorithm. The automaton is in fact a trie and the failure function is a breadth-first traversal of the trie.

Answering Queries on Binary array

Given a binary array of length <=10^5 and almost equal number of queries. Each query is given by two integers (l,r) for each query we have to computer the total number of consecutive 0's and 1's in the range [l,r].
If n is the length of the array then 1 <= l < r <= n.
For example:
if the binary array (1-indexed) is "011000" and say there are 5 queries:
1 3
5 6
1 5
3 6
3 4
Then the required answer is
1
1
2
2
0
I am aware that this can be solved by a linear time (worst case) algorithm for each query but due to the large number of queries it's not feasible.
Just wondering which is the most efficient way to achieve this?
You can do it with O(n) space complexity and O(log(n)) search time for each query. Calculate the counts for windows of size 1, 2, 4, .... For a given query you can find O(log(n)) windows (at most 2 windows of a particular size), summing which you can find your answer.
As Dukeling said in the comments, you can preprocess in O(n) to compute an array B where B[x] contains the total number of consecutive digits seen in [1..r].
This allows a query in O(1) to find the number of consecutive digits in the range [l,r] by using the array to count the total number in the range [1,r] and subtracting the number in the range [1,l].
Python code:
def preprocess(A):
last=A[0]
B=[0,0]
num_consecutive=0
for a in A[1:]:
if a==last:
num_consecutive+=1
B.append(num_consecutive)
last=a
return B
def query(B,l,r):
return B[r]-B[l]
A=[0,1,1,0,0,0]
B=preprocess(A)
print query(B,1,3)
print query(B,5,6)
print query(B,1,5)
print query(B,3,6)
print query(B,3,4)

Adding one digit (0-9) to the sequence/string creates new 4 digits number

I'm trying to find an algorithm which "breaks the safe" by typing the keys 0-9. The code is 4 digits long. The safe will be open where it identifies the code as substring of the typing. meaning, if the code is "3456" so the next typing will open the safe: "123456". (It just means that the safe is not restarting every 4 keys input).
Is there an algorithm which every time it add one digit to the sequence, it creates new 4 digits number (new combinations of the last 4 digits of the sequence\string)?
thanks, km.
Editing (I post it years ago):
The question is how to make sure that every time I set an input (one digit) to the safe, I generate a new 4 digit code that was not generated before. For example, if the safe gets binary code with 3 digits long then this should be my input sequence:
0001011100
Because for every input I get a new code (3 digit long) that was not generated before:
000 -> 000
1 -> 001
0 -> 010
1 -> 101
1 -> 011
1 -> 111
0 -> 110
0 -> 100
I found a reduction to your problem:
Lets define directed graph G = (V,E) in the following way:
V = {all possible combinations of the code}.
E = {< u,v > | v can be obtained from u by adding 1 digit (at the end), and delete the first digit}.
|V| = 10^4.
Din and Dout of every vertex equal to 10 => |E| = 10^5.
You need to prove that there is Hamilton cycle in G - if you do, you can prove the existence of a solution.
EDIT1:
The algorithm:
Construct directed graph G as mentioned above.
Calculate Hamilton cycle - {v1,v2,..,vn-1,v1}.
Press every number in v1.
X <- v1.
while the safe isn't open:
5.1 X <- next vertex in the Hamilton path after X.
5.2 press the last digit in X.
We can see that because we use Hamilton cycle, we never repeat the same substring. (The last 4 presses).
EDIT2:
Of course Hamilton path is sufficient.
Here in summary is the problem I think you are trying to solve and some explanation on how i might approach solving it. http://www.cs.swan.ac.uk/~csharold/cpp/SPAEcpp.pdf
You have to do some finessing to make it fit into the chinese post man problem however...
Imagine solving this problem for the binary digits, three digits strings. Assume you have the first two digits, and ask your self what are my options to move to? (In regards to the next two digit string?)
You are left with a Directed Graph.
/-\
/ V
\- 00 ----> 01
^ / ^|
\/ ||
/\ ||
V \ |V
/-- 11 ---> 10
\ ^
\-/
Solve the Chinese Postman, you will have all combinations and will form one string
The question is now, is the Chinese postman solvable? There are algorithms which determine weather or not a DAG is solvable for the CPP, but i don't know if this particular graph is necessarily solvable based on the problem alone. That would be a good thing to determine. You do however know you could find out algorithmically weather it is solvable and if it is you could solve it using algorithms available in that paper (I think) and online.
Every vertex here has 2 incoming edges and 2 outgoing edges.
There are 4 (2^2) vertexes.
In the full sized problem there are 19683( 3 ^ 9 ) vertexs and every vertex has 512 ( 2 ^ 9 ) out going and incoming vertexes. There would be a total of
19683( 3 ^ 9 ) x 512 (2 ^ 9) = 10077696 edges in your graph.
Approach to solution:
1.) Create list of all 3 digit numbers 000 to 999.
2.) Create edges for all numbers such that last two digits of first number match first
two digits of next number.
ie 123 -> 238 (valid edge) 123 -> 128 (invalid edge)
3.) use Chinese Postman solving algorithmic approaches to discover if solvable and
solve
I would create an array of subsequences which needs to be updates upon any insertion of a new digit. So in your example, it will start as:
array = {1}
then
array = {1,2,12}
then
array = {1,2,12,3,13,23,123}
then
array = {1,2,12,3,13,23,123,4,14,24,124,34,134,234,1234}
and when you have a sequence that is already at the length=4 you don't need to continue the concatenation, just remove the 1st digit of the sequence and insert the new digit at the end, for example, use the last item 1234, when we add 5 it will become 2345 as follows:
array = {1,2,12,3,13,23,123,4,14,24,124,34,134,234,1234,5,15,25,125,35,135,235,1235,45,145,245,1245,345,1345,2345,2345}
I believe that this is not a very complicated way of going over all the sub-sequences of a given sequence.

Fastest way to Find a m x n submatrix in M X N matrix

I was thinking of a fast method to look for a submatrix m in a bigger mtrix M.
I also need to identify partial matches.
Couple of approaches I could think of are :
Optimize the normal bruteforce to process only incremental rows and columns.
May be extend Rabin-karp algorithm to 2-d but not sure how to handle partial matches with it.
I believe this is quite frequently encountered problem in image processing and would appreciate if someone could pour in their inputs or point me to resources/papers on this topic.
EDIT:
Smaller example:
Bigger matrix:
1 2 3 4 5
4 5 6 7 8
9 7 6 5 2
Smaller Matrix:
7 8
5 2
Result: (row: 1 col: 3)
An example of Smaller matrix which qualifies as a partial match at (1, 3):
7 9
5 2
If More than half of pixels match, then it is taken as partial match.
Thanks.
I recommend doing an internet search on "2d pattern matching algorithms". You'll get plenty of results. I'll just link the first hit on Google, a paper that presents an algorithm for your problem.
You can also take a look at the citations at the end of the paper to get an idea of other existing algorithms.
The abstract:
An algorithm for searching for a two dimensional m x m pattern in a two dimensional n x n text is presented. It performs on the average less comparisons than the size of the text: n^2/m using m^2 extra space. Basically, it uses multiple string matching on only n/m rows of the text. It runs in at most 2n^2 time and is close to the optimal n^2 time for many patterns. It steadily extends to an alphabet-independent algorithm with a similar worst case. Experimental results are included for a practical version.
There are very fast algorithms for this if you are willing to preprocess the matrix and if you have many queries for the same matrix.
Have a look at the papers on Algebraic Databases by the Research group on Multimedia Databases (Prof. Clausen, University of Bonn). Have a look at this paper for example: http://www-mmdb.iai.uni-bonn.de/download/publications/sigir-03.pdf
The basic idea is to generalize inverted list, so they use any kind of algebraic transformation, instead of just shifts in one direction as with ordinary inverted lists.
This means that this approach works whenever the modifications you need to do to the input data can be modelled algebraically. This specifically that queries which are translated in any number of dimensions, rotated, flipped etc can all be retrieved.
The paper is mainly showing this for musical data, since this is their main research interest, but you might be able to find others, which show how to adapt this to image data as well (or you can try to adapt it yourself, if you understand the principle it's quite simple).
Edit:
This idea also works with partial matches, if you define them correctly.
There is no way to do this fast if you only ever need to match one small matrix against one big matrix. But if you need to do many small matrices against big matrices, then preprocess the big matrix.
A simple example, exact match, many 3x3 matrices against one giant matrix.
Make a new "match matrix", same size as "big matrix", For each location in big matrix compute a 3x3 hash for each x,y to x+3,y+3 in big matrix. Now you just scan the match matrix for matching hashes.
You can achieve partial matches with specialized hash functions that give the same hash to things that have the same partial matching properties. Tricky.
If you want to speed up further and have memory for it, create a hash table for the match matrix, and lookup the hashes in the hash table.
The 3x3 solution will work for any test matrix 3x3 or larger. You don't need to have a perfect hash method - you need just something that will reject the majority of bad matches, and then do a full match for potential matches in the hash table.
I think you cannot just guess where the submatrix is with some approach, but you can optimize your searching.
For example, given a matrix A MxN and a submatrix B mxn, you can do like:
SearchSubMatrix (Matrix A, Matrix B)
answer = (-1, -1)
Loop1:
for i = 0 ... (M-m-1)
|
| for j = 0 ... (N-n-1)
| |
| | bool found = true
| |
| | if A[i][j] = B[0][0] then
| | |
| | | Loop2:
| | | for r = 0 ... (m-1)
| | | | for s = 0 ... (n-1)
| | | | | if B[r][s] != A[r+i][s+j] then
| | | | | | found = false
| | | | | | break Loop2
| |
| | if found then
| | | answer = (i, j)
| | | break Loop1
|
return answer
Doing this, you will reduce your search in the reason of the size of the submatrix.
Matrix Submatrix Worst Case:
1 2 3 4 2 4 [1][2][3] 4
4 3 2 1 3 2 [4][3][2] 1
1 3 2 4 [1][3]{2 4}
4 1 3 2 4 1 {3 2}
(M-m+1)(N-n+1) = (4-2+1)(4-2+1) = 9
Although this is O(M*N), it will never look M*N times, unless your submatrix has only 1 dimension.

The Art of Computer Programming exercise question: Chapter 1, Question 8

I'm doing the exercises to TAOCP Volume 1 Edition 3 and have trouble understanding the syntax used in the answer to the following exercise.
Chapter 1 Exercise 8
Computing the greatest common divisor of positive integers m & n by specifying Tj,sj,aj,bj
Let your input be represented by the string ambn (m a's followed by n b's)
Answer:
Let A = {a,b,c}, N=5. The algorithm will terminate with the string agcd(m,n)
j Tj sj bj aj
0 ab (empty) 1 2 Remove one a and one b, or go to 2.
1 (empty) c 0 0 Add c at extreme left, go back to 0.
2 a b 2 3 Change all a's to b's
3 c a 3 4 Change all c's to a's
4 b b 0 5 if b's remain, repeat
The part that I have trouble understanding is simply how to interpret this table.
Also, when Knuth says this will terminate with the string agcd(m,n) -- why the superscript for gcd(m,n) ?
Thanks for any help!
Edited with more questions:
What is Tj -- note that T = Theta
What is sj -- note that s = phi
How do you interpret columns bj and aj?
Why does Knuth switch a new notation in the solution to an example that he doesn't explain in the text? Just frustrating. Thanks!!!
Here's an implementation of that exercise answer. Perhaps it helps.
By the way, the table seems to describe a Markov algorithm.
As far as I understand so far, you start with the first command set, j = 0. Replace any occurencies of Tj with sj and jump to the next command line depending on if you replaced anything (in that case jump to bj, if nothing has been replaced, jump to aj).
EDIT: New answers:
A = {a,b,c} seems to be the character set you can operate with. c comes in during the algorithm (added to the left and later replaced by a's again).
Theta and phi could be some greek character you usually use for something like "original" and "replacement", although I wouldn't know they are.
bj and aj are the table lines to be next executed. This matches with the human-readable descriptions in the last column.
The only thing I can't answer is why Knuth uses this notation without any explanations. I browsed the first chapters and the solutions in the book again and he doesn't mention it anywhere.
EDIT2: Example for gdc(2,2) = 2
Input string: aabb
Line 0: Remove one a and one b, or go to 2.
=> ab => go to 1
Line 1: Add c at extreme left, go back to 0.
=> cab => go to 0
Line 0: Remove one a and one b, or go to 2.
=> c => go to 1
Line 1: Add c at extreme left, go back to 0.
=> cc => go to 0
Line 0: Remove one a and one b, or go to 2.
No ab found, so go to 2
Line 2: Change all a's to b's
No a's found, so go to 3
Line 3: Change all c's to a's
=> aa
Line 4: if b's remain, repeat
No b's found, so go to 5 (end).
=> Answer is "aa" => gdc(2,2) = 2
By the way, I think description to line 1 should be "Remove one "ab", or go to 2." This makes things a bit clearer.
The superscript for gcd(m,n) is due to how numbers are being represented in this table.
For example: m => a^m
n => b^n
gcd(m,n) => a^gcd(m,n)
It looks to be like Euclids algorithm is being implemented.
i.e.
gcd(m,n):
if n==0:
return m
return gcd(n,m%n)
The numbers are represented as powers so as to be able to do the modulo operation m%n.
For example, 4 % 3, will be computed as follows:
4 'a's (a^4) mod 3 'b's (b^3), which will leave 1 'a' (a^1).
the notion of am is probably a notion of input string in the state machine context.
Such notion is used to refer to m instances of consecutive a, i.e.:
a4 = aaaa
b7 = bbbbbbb
a4b7a3 = aaaabbbbbbbaaa
And what agcd(m,n) means is that after running the (solution) state machine, the resulting string should be gcd(m,n) instances of a
In other words, the number of a's in the result should be equal to the result of gcd(m,n)
And I agree with #schnaader in that it's probably a table describing Markov algorithm usages.