Solution to Problem 2: Treasure Hunt
At any point in his search for the treasure, Muttal has with him
a token and card. The card tells him which machine to go to and
the token is the one he is to insert into that machine. Since we
are given a table that tells us for each machine and token, what
would be his next machine and next token, knowing the current
token and current machine gives us a complete description of what
he would do in the future.
The naive solution simply simulates the actions of Muttal.
--------------------------------------------------------------
/* We assume that there are two 2-dimensional array Tok and Mac
where Tok[i][j] is the token spat out by the ith machine when
token j is inserted into it. Mac[i][j] is the machine number
printed on the card spat out when token j is inserted into the
ith machine */
c-token=1 /* The current token is 1
c-machine=S /* We begin with machine S
for (i=2 to W) {
tmp-token = Tok[c-machine][c-token]
tmp-machine=Mac[c-machine][c-token]
c-token = tmp-token /* get the next token*/
c-machine = tmp-machine /* get the next machine*/
}
print c-machine
-----------------------------------------------------------------
This algorithm takes time proportional to W. And as indicated in
the problem statment if W can be large (of the order of 10^9) and
then this is not good enough.
The observation that will help us cut this down considerably is
the following: Suppose the sequence of (Machine,Token) pairs that
Muttal goes through is given by
(m_1,t_1) (m_2,t_2) .... (m_k,t_k) (m_k+1,t_k+1) .... (m_n,t_n) ....
(where m_1 is S and t_1 is 1). Then
if m_k = m_n and t_k=t_n, the above sequence would actually like
(m_1,t_1) (m_2,t_2) ... (m_k,t_k)(m_k+1,t_k+1) ...
(m_k,t_k)(m_k+1,t_k+1) ... (m_k,t_k)...
Starting at machine m_k and with token t_k in hand if he ends up
at (m_k,t_k) again, he has no choice but to go through the same
sequence and end up (m_k,t_k) again and so on.
That is, his futile walk would look like
(m_1,t_1)(m_2,t_2)...(m_k-1,t_k-1) r r r r ...
where r = (m_k,t_k),(m_k+1,t_k+1) ... (m_n-1,t_n-1)
Let l be the length of r, that is l = n-k. We know that the
machine reached at steps k, k+l, k+2l, ... is m_k (and the token
on hand is t_k). Similarly the machines reached at step k+1,
k+1+l, k+1+2l, ... is m_k+1 and so on.
Thus, for any N > k we can determine the machine reached as
follows: Let N = k+N'. The machine reached at set N is N' mod l.
Thus, it suffices to simulate Muttal's walk till we find a
repeating machine/token pair.
The question then is, how soon would a pair (m_k,t_k) repeat?
Notice that there are only |M| x |T| possible choices for (m,t).
So, no matter what the table (describing the next machine and next
token) looks like, within the first (|M| x |T| + 1) steps we are
guaranteed to find a repetition!
The algorithm incorporating the above idea is described below:
--------------------------------------------------------------
/* We assume that there are two 2-dimensional array Tok and Mac
where Tok[i][j] is the token spat out by the ith machine when
token j is inserted into it. Mac[i][j] is the machine number
printed on the card spat out when token j is inserted into the
ith machine */
count = 1 /* To keep track of how many
(machine,token) pairs have been seen */
c-token=1 /* The current token is 1
c-machine=S /* We begin with machine S
visited[count][0]=ctoken /* store the pair */
visited[count][1]=c-machine
count=count+1
for (i=2 to |M|*|T|+1) {
tmp-token = Tok[c-machine][c-token]
tmp-machine=Mac[c-machine][c-token]
c-token = tmp-token /* get the next token*/
c-machine = tmp-machine /* get the next machine*/
for (k=1 to count-1) { /* check if the pair has been seen
if ((visited[k][0]=c-token) and (visited[k][1]=c-machine)) {
/* if so we are done*/
l = count-k
j = (W - k) % l /* m_j+k = m_W, as discussed above
print (visited[j+k][1])
return
}
}
/* if W is less that |M|*|T|+1 we will might find the
answer before the pair repeats */
if (i = W) {
print(c-machine)
return
}
}
-----------------------------------------------------------------
The outer loop executes at most |M|*|T|+1 times and the inner
loop can run at most as many steps as the number of pairs visited
(which cannot exceed |M|*|T|+1). Thus the above algorithm will
take roughly (|M|*|T|+1)^2 steps in the worst case.