Copy an oder list to another oder list [duplicate] - algorithm

Although I have no problem whatsoever understanding recursion, I can't seem to wrap my head around the recursive solution to the Tower of Hanoi problem. Here is the code from Wikipedia:
procedure Hanoi(n: integer; source, dest, by: char);
Begin
if (n=1) then
writeln('Move the plate from ', source, ' to ', dest)
else begin
Hanoi(n-1, source, by, dest);
writeln('Move the plate from ', source, ' to ', dest);
Hanoi(n-1, by, dest, source);
end;
End;
I understand the base case and the concept of breaking the problem into smaller pieces until you are able to move a single disk. However, I can't figure out how the two recursive calls in the non-base case work together. Perhaps someone can help me out? Thanks.

Actually, the section from where you took that code offers an explanation as well:
To move n discs from peg A to peg C:
move n−1 discs from A to B. This leaves disc #n alone on peg A
move disc #n from A to C
move n−1 discs from B to C so they sit on disc #n
It's pretty clear that you first have to remove n − 1 discs to get access to the nth one. And that you have to move them first to another peg than where you want the full tower to appear.
The code in your post has three arguments, besides the number of discs: A source peg, a destination peg and a temporary peg on which discs can be stored in between (where every disc with size n − 1 fits).
The recursion happens actually twice, there, once before the writeln, once after. The one before the writeln will move n − 1 discs onto the temporary peg, using the destination peg as temporary storage (the arguments in the recursive call are in different order). After that, the remaining disc will be moved to the destination peg and afterwards the second recursion compeltes the moving of the entire tower, by moving the n − 1 tower from the temp peg to the destination peg, above disc n.

a year ago i had i functional programming course and draw this illustration for the algorithm.
hope it helps!
(0) _|_ | |
__|__ | |
___|___ | |
____|____ ____|____ ____|____
(1.1) | | |
__|__ | |
___|___ _|_ |
____|____ ____|____ ____|____ (A -> B)
(1.2) | | |
| | |
___|___ _|_ __|__
____|____ ____|____ ____|____ (A -> C)
(1.3) | | |
| | _|_
___|___ | __|__
____|____ ____|____ ____|____ (B -> C)
(2.1) | | |
| | _|_
| ___|___ __|__
____|____ ____|____ ____|____ (A -> B)
(3.1) | | |
| | |
_|_ ___|___ __|__
____|____ ____|____ ____|____ (C -> A)
(3.2) | | |
| __|__ |
_|_ ___|___ |
____|____ ____|____ ____|____ (C -> B)
(3.3) | _|_ |
| __|__ |
| ___|___ |
____|____ ____|____ ____|____ (A -> B)
The 3 rings problem has been splited to 2 2-rings problem (1.x and 3.x)

There's a good explanation of the recursive Hanoi implementation at http://www.cs.cmu.edu/~cburch/survey/recurse/hanoiimpl.html.
Summary is, if you want to move the bottom plate from stick A to stick B, you first have to move all the smaller plates on top of it from A to C. The second recursive call is then to move the plates you moved to C back onto B after your base case moved the single large plate from A to B.

I agree this one isn't immediate when you first look at it, but it's fairly simple when you get down to it.
Base case: your tower is of size 1. So you can do it in one move, from source directly to dest.
Recursive case: your tower is of size n > 1. So you move the top tower of size n-1 to an extra peg (by), move the bottom "tower" of size 1 to the destination peg, and move the top tower from by to dest.
So with a simple case, you have a tower of height 2:
_|_ | |
__|__ | |
===== ===== =====
First step: move the top tower of 2-1 (=1) to the extra peg (the middle one, lets say).
| | |
__|__ _|_ |
===== ===== =====
Next: move the bottom disc to the destination:
| | |
| _|_ __|__
===== ===== =====
And finally, move the top tower of (2-1)=1 to the destination.
| | _|_
| | __|__
===== ===== =====
If you think about it, even if the tower were 3 or more, there will always be an empty extra peg, or a peg with all larger discs, for the recursion to use when swapping towers around.

Suppose we want to move a disc from A to C through B then:
move a smaller disc to B.
move another disc to C.
move B to C.
move from A to B.
move all from C to A.
If you repeat all the above steps, the disc will transfer.

I feel the pain!
Although this is an old post, I think what one really needs to understand, is not the "move this to that" approach but that the answer involves using the side-effect of the recursion.
A invaluable help to me was the "The Little Schemer" which teaches one to think and write recursive functions.
However, this teaches the reader to use the results of the returned result in the next recursive call.
In the Tower of Hanoi, the answer is not in the returned result per se, but in the observation of the returned result.
The magic occurs in the succesive rearrangment of the function parameters.
Yes the problem is really in three parts:
moving a smaller tower to the spare peg
moving the last disc to the destination peg
moving the remaining tower on the spare peg to the destination peg.
In Scheme:
(define (th n a b c)
(if (zero? n) 'done
(begin
(th (- n 1) a c b)
(display (list a c))
(newline)
(th (- n 1) b a c))))
(th 5 'source 'spare 'destination)
However it is the displaying of the function parameters which is the solution to the problem and crucially understanding the double tree like structure of the calls.
The solution also conveys the power of proof by induction and a warm glow to all programmers who have wrestled with conventional control structures.
Incidently, to solve the problem by hand is quite satisfying.
count the number of discs
if even, move the first disc to the spare peg, make next legal move (not involving the top disc). Then move the top disc to the destination peg, make the next legal move(nittd). Then move the top disc to the source peg, make the next legal move(nittd)...
if odd, move the first disc to the destination peg, make the next legal move (not involving the top disc). Then move the top disc to the spare peg, make the next legal move(nittd). Then move the top disc to the source peg, make the next legal move(nittd)...
Best done by always holding the top disc with the same hand and always moving that hand in the same direction.
The final number of moves for n discs is 2^n - 1 the move n disc to destination is halfway through the process.
Lastly, it is funny how explaining a problem to a colleague, your wife/husband or even the dog (even it they not listening) can cement enlightenment.

After reading all these explanations I thought I'd weigh in with the method my professor used to explain the Towers of Hanoi recursive solution. Here is the algorithm again with n representing the number of rings, and A, B, C representing the pegs. The first parameter of the function is the number of rings, second parameter represents the source peg, the third is the destination peg, and fourth is the spare peg.
procedure Hanoi(n, A, B, C);
if n == 1
move ring n from peg A to peg B
else
Hanoi(n-1, A, C, B);
move ring n-1 from A to C
Hanoi(n-1, C, B, A);
end;
I was taught in graduate school to never to be ashamed to think small. So, let's look at this algorithm for n = 5. The question to ask yourself first is if I want to move the 5th ring from A to B, where are the other 4 rings? If the 5th ring occupies peg A and we want to move it to peg B, then the other 4 rings can only be on peg C. In the algorithm above the function Hanoi (n-1, A, C, B) is trying to move all those 4 other rings on to peg C, so ring 5 will be able to move from A to B. Following this algorithm we look at n = 4. If ring 4 will be moved from A to C, where are rings 3 and smaller? They can only be on peg B. Next, for n = 3, if ring 3 will be moved from A to B, where are rings 2 and 1? On peg C of course. If you continue to follow this pattern you can visualize what the recursive algorithm is doing. This approach differs from the novice's approach in that it looks at the last disk first and the first disk last.

Here goes the explanation. Look at the picture ->
By calling Movetower(3,a,b,c), you intend to move all the 3 discs from tower A to tower B. So the sequential calls are ->
1. Movetower(3,a,b,c) // No Move needed
2. Movetower(2,a,c,b) // No move needed
3. Movetower(1,a,b,c) // Here is the time to move, move disc1 from a to b
4. Movetower(2,a,c,b) // Returning to this call again, this is the time to move disc2 from a to c
5. Movetower(1,b,c,a) // Again the time to move, this time disc1 from b to c
6. Movetower(3,a,b,c) // Returning to this call again, this is the time to move disc3 from a to b
7. Movetower(2,c,b,a) // Not the time to move
8. Movetower(1,c,a,b) // Here is the time to move, move disc1 from c to a
9. Movetower(2,c,b,a) // Returning to this call again, this is the time to move disc2 from c to b
10.Movetower(1,c,a,b) // Here is the time to move, move disc1 from a to b
Hope it helps :)
For Animation : https://www.cs.cmu.edu/~cburch/survey/recurse/hanoiex.html

Think of it as a stack with the disks diameter being represented by integers (4,3,2,1)
The first recursion call will be called 3 times and thus filling the run-time stack as follows
first call : 1. Second call : 2,1. and third call: 3,2,1.
After the first recursion ends, the contents of the run-time stack is popped to the middle pole from largest diameter to smallest (first in last out). Next, disk with diameter 4 is moved to the destination.
The second recursion call is the same as the first with the exception of moving the elements from the middle pole to destination.

The first recursive call moves all the pieces except the biggest one from source to by using dest as the auxilary pile. When done all the pieces except the biggest will lie on by and the biggest one is free. Now you can move the biggest one to dest and use another recursive call to move all the pieces from by to dest.
The recursive calls won't know anything about the biggest piece (i.e. they will ignore it), but that's ok because the recursive calls will only deal with the pieces that are smaller and thus can be moved onto and off the biggest piece freely.

It's simple. Suppose you want to move from A to C
if there's only one disk, just move it.
If there's more than one disk, do
move all disks (n-1 disks), except the bottom one from A to B
move the bottom disk from A to C
move the n-1 disks from the first step from A to C
Keep in mind that, when moving the n-1 disks, the nth won't be a problem at all (once it is bigger than all the others)
Note that moving the n-1 disks recurs on the same problem again, until n-1 = 1, in which case you'll be on the first if (where you should just move it).

The answer for the question, how does the program know, that even is "src" to "aux", and odd is "src" to "dst" for the opening move lies in the program. If you break down fist move with 4 discs, then this looks like this:
hanoi(4, "src", "aux", "dst");
if (disc > 0) {
hanoi(3, 'src', 'dst', 'aux');
if (disc > 0) {
hanoi(2, 'src', 'aux', 'dst');
if (disc > 0) {
hanoi(1, 'src', 'dst', 'aux');
if (disc > 0) {
hanoi(0, 'src', 'aux', 'dst');
END
document.writeln("Move disc" + 1 + "from" + Src + "to" + Aux);
hanoi(0, 'aux', 'src', 'dst');
END
}
also the first move with 4 disc(even) goes from Src to Aux.

public static void hanoi(int number, String source, String aux, String dest)
{
if (number == 1)
{
System.out.println(source + " - > "+dest);
}
else{
hanoi(number -1, source, dest, aux);
hanoi(1, source, aux, dest);
hanoi(number -1, aux, source, dest);
}
}

void TOH(int n, int a, int b){
/*Assuming a as source stack numbered as 1, b as spare stack numbered as 2 and c as target stack numbered as 3. So once we know values of a and b, we can determine c as there sum is a constant number (3+2+1=)6.
*/
int c = 6-a-b;
if(n==1){
cout<<"Move from "<<a<<" to "<<b<<"\n";
}
else{
// Move n-1 disks from 1st to 2nd stack. As we are not allowed to move more than one disks at a time, we do it by recursion. Breaking the problem into a simpler problem.
TOH(n-1, a, c);
// Move the last alone disk from 1st to 3rd stack.
TOH(1, a, b);
// Put n-1 disks from 2nd to 3rd stack. As we are not allowed to move more than one disks at a time, we do it by recursion. Breaking the problem into a simpler problem.
TOH(n-1, c, b);
}
}
int main() {
TOH(2, 1, 3);
cout<<"FINISHED \n";
TOH(3, 1, 3);
cout<<"FINISHED \n";
TOH(4, 1, 3);
return 0;
}

There are three towers namely source tower, destination tower and helper tower. The source tower has all the disks and your target is to move all the disks to the destination tower and make sure in doing so, you never put a larger disk on top of a smaller disk. We can solve this problem using recursion in the steps below:
We have n numbers of disks on source tower
Base case: n=1
If there is only one disk in source tower, move it to destination tower.
Recursive case: n >1
Move the top n-1 disks from from source tower to helper tower
Move the only remaining, the nth disk(after step1) to destination
tower
Move the n-1 disks that are in helper tower now, to destination
tower, using source tower as a helper.
Source code in Java:
private void towersOfHanoi(int n, char source, char destination, char helper) {
//Base case, If there is only one disk move it direct from source to destination
if(n==1){
System.out.println("Move from "+source+" to "+destination);
}
else{
//Step1: Move the top n-1 disks from source to helper
towersOfHanoi(n-1, source, helper, destination);
//Step2: Move the nth disk from source to destination
System.out.println("Move from "+source+" to "+destination);
/*Step3: Move the n-1 disks(those you moved from source to helper in step1)
* from helper to destination, using source(empty after step2) as helper
*/
towersOfHanoi(n-1, helper, destination, source);
}
}

As some of our friends suggested, I removed previous two answers and I consolidate here.
This gives you the clear understanding.
What the general algorithm is....
Algorithm:
solve(n,s,i,d) //solve n discs from s to d, s-source i-intermediate d-destination
{
if(n==0)return;
solve(n-1,s,d,i); // solve n-1 discs from s to i Note:recursive call, not just move
move from s to d; // after moving n-1 discs from s to d, a left disc in s is moved to d
solve(n-1,i,s,d); // we have left n-1 disc in 'i', so bringing it to from i to d (recursive call)
}
here is the working example Click here

As a CS student, you might have heard about Mathematical induction.
The recursive solution of Tower of Hanoi works analogously - only different part is to really get not lost with B and C as were the full tower ends up.

In simple sense the idea is to fill another tower among the three defined towers in the same order of discs as present without a larger disc overlapping a small disc at any time during the procedure.
Let 'A' , 'B' and 'C' be three towers. 'A' will be the tower containing 'n' discs initially. 'B' can be used as intermediate tower and 'C' is the target tower.
The algo is as follows:
Move n-1 discs from tower 'A' to 'B' using 'C'
Move a disc from 'A' to 'C'
Move n-1 discs from tower 'B' to 'C' using 'A'
The code is as follows in java:
public class TowerOfHanoi {
public void TOH(int n, int A , int B , int C){
if (n>0){
TOH(n-1,A,C,B);
System.out.println("Move a disk from tower "+A +" to tower " + C);
TOH(n-1,B,A,C);
}
}
public static void main(String[] args) {
new TowerOfHanoi().TOH(3, 1, 2, 3);
}
}

Here is my solution code to Towers of Hanoi problem using recursion with golang. `package main
import "fmt"
func main() {
toi(4, "src", "dest", "swap")
}
func toi(n int, from, to, swap string) {
if n == 0 {
return
}
if n == 1 {
fmt.Printf("mov %v %v -> %v\n", n, from, to)
return
}
toi(n-1, from, swap, to)
fmt.Printf("mov %v %v -> %v\n", n, from, to)
toi(n-1, swap, to, from)
}`

This python3 example uses a recursive solution:
# Hanoi towers puzzle
# for each n, you have to move n-1 disks off the n disk onto another peg
# then you move the n disk to a free peg
# then you move the n-1 disks on the other peg back onto the n disk
def hanoi(n):
if n == 1:
return 1
else:
return hanoi(n-1) + 1 + hanoi(n-1)
for i in range(1, 11):
print(f"n={i}, moves={hanoi(i)}")
Output:
n=1, moves=1
n=2, moves=3
n=3, moves=7
n=4, moves=15
n=5, moves=31
n=6, moves=63
n=7, moves=127
n=8, moves=255
n=9, moves=511
n=10, moves=1023
But of course the most efficient way to work out how many moves is to realise that the answers are always 1 less than 2^n. So the mathematical solution is 2^n - 1

Just saw this video today: Recursion 'Super Power' (in Python) - Computerphile and I think we should definitely have Professor Thorsten Altenkirch's code in here as its a very beautiful and elegant piece of recursion code and its not always that we have a quality video to show in an answer.
def move(f,t) :
print("move disc from {} to {}!".format(f,t))
def hanoi(n,f,h,t) :
if n==0 :
pass
else :
hanoi(n-1,f,t,h)
move(f,t)
hanoi(n-1,h,f,t)
our hanoi function has 4 parameters:
n: number of discs
f: origin where discs are (from)
h: intermediate step 'via' (helper)
t: final position where we want the discs to be in the end (target)
>>> hanoi(4,"A","B","C")
move disc from A to B!
move disc from A to C!
move disc from B to C!
move disc from A to B!
move disc from C to A!
move disc from C to B!
move disc from A to B!
move disc from A to C!
move disc from B to C!
move disc from B to A!
move disc from C to A!
move disc from B to C!
move disc from A to B!
move disc from A to C!
move disc from B to C!

I made a small change to the code here, if you look at the output you can see the small parts pattern are repeating in the parent nodes (Think of it as fractal images)
def moveTower(height,fromPole, toPole, withPole, ar = ''):
if height >= 1:
print( " "*(3-height), "moveTower:", height, fromPole, toPole, ar )
moveTower(height-1,fromPole,withPole,toPole)
moveDisk(fromPole,toPole,height)
moveTower(height-1,withPole,toPole,fromPole, '*')
#print(withPole)
def moveDisk(fp,tp,height):
print(" "*(4-height), "moving disk", "~"*(height), "from",fp,"to",tp)
moveTower(3,"A","B","C")
And the output is:
moveTower: 3 A B
moveTower: 2 A C
moveTower: 1 A B
moving disk ~ from A to B
moving disk ~~ from A to C
moveTower: 1 B C *
moving disk ~ from B to C
moving disk ~~~ from A to B
moveTower: 2 C B *
moveTower: 1 C A
moving disk ~ from C to A
moving disk ~~ from C to B
moveTower: 1 A B *
moving disk ~ from A to B

This is code in C++ for Tower of Hanoi, which is recursively called.
#include <iostream>
void toh(int n, char A, char B, char C) {
if(n == 1) {
std::cout << "Move Disc 1 from " << A << " to " << C << std::endl;
return;
}
toh(n-1, A, C, B);
std::cout << "Move Disc " << n << " from " << A << " to " << C <<std::endl;
toh(n-1, B, A, C);
}
int main() {
int numberOfDisc;
char A = 'A', B = 'B', C = 'C';
std::cout << "Enter the number of disc: ";
std::cin >> numberOfDisc;
toh(numberOfDisc, A, B, C);
return 0;
}

I highly recommend this video which illustrates the recursion for this problem in a very understandable way.
The key is to understand the repeating pattern in the solution. The problem can be divided into three main sub-problems. Assuming you have n disks that they are placed at rod A. The target rod is C, and you have B as an intermediate.
Main problem; move n disks from rod A to rod C by using rod B.
Move n-1 disks from rod A to rod B by using rod C.
Move the last disk from rod A to rod C.
Move n-1 disks from rod B to rod C by using rod A.
Sub-problems 1 and 3 are actually solved within the same problem division you see above.
Lets take sub problem 1.
Sub-problem 1; move n-1 disks from rod A to rod B by using rod C.
Move n-2 disks from rod A to rod C by using rod B.
Move the last disk from rod A to rod B.
Move n-2 disks from rod C to rod B by using rod A.
We solve the sub-problem in the same way we solve the main-problem. Our base case will be when the number of disks are equal to 1 then we move it from one rod to target one, that's it.
Writing down these steps will help tremendously.

I actually found a very good explanation for this at https://helloml.org/tower-of-hanoi-recursion/. I recommend you to check it out.
In this article, they have mentioned the steps to solve this problem.
Steps to solve the Tower of Hanoi Problem:
Move 'n-1' disks recursively from the source rod to the auxiliary rod.
Move the nth disc from source rod to destination rod.
Move 'n-1' disks recursively from the auxiliary rod to the destination rod.
It considers a case of three disks and explains the algorithm with a set of images.

Tower (N,source,aux.dest):
if N =1 Then
Write : Source -> dest
return
end of if
move N-1 disk from peg source to peg aux
call Tower (N-1, source, dest, aux)
write source -> dest
move N-1 disks from peg aux to peg dest
call Tower (N-1, source, dest, aux)
return

/**
*
*/
package com.test.recursion;
/**
* #author kamals1986 The Recursive algorithm for Tower of Hanoi Problem The
* algorithm grows by power(2,n).
*/
public class TowerOfHanoi {
private static String SOURCE_PEG = "B";
private static String SPARE_PEG = "C";
private static String TARGET_PEG = "A";
public void listSteps(int n, String source, String target, String spare) {
if (n == 1) {
System.out.println("Please move from Peg " + source + "\tTo Peg\t"
+ target);
} else {
listSteps(n - 1, source, spare, target);
listSteps(1, source, target, spare);
listSteps(n - 1, spare, target, source);
}
}
public static void main(String[] args) {
long startTime = System.currentTimeMillis();
new TowerOfHanoi().listSteps(18, SOURCE_PEG, TARGET_PEG, SPARE_PEG);
long endTime = System.currentTimeMillis();
System.out.println("Done in " + (endTime - startTime) / 1000
+ "\t seconds");
}
}

def Hanoi(n, A, B, C):
if(n==1): print "move plates to empty peg"
else:
Hanoi(n-1, A, B, C)
print "move"+str(n)+" to peg "+C
Hanoi(n-1, B, C, A)

I am trying to get recursion too.
I found a way i think,
i think of it like a chain of steps(the step isnt constant it may change depending on the previous node)
I have to figure out 2 things:
previous node
step kind
after the step what else before call(this is the argument for the next call
example
factorial
1,2,6,24,120 ......... or
1,2*(1),3*(2*1),4*(3*2*1,5*(4*3*2*1)
step=multiple by last node
after the step what i need to get to the next node,abstract 1
ok
function =
n*f(n-1)
its 2 steps process
from a-->to step--->b
i hoped this help,just think about 2 thniks,not how to get from node to node,but node-->step-->node
node-->step is the body of the function
step-->node is the arguments of the other function
bye:) hope i helped

Related

Finding the minimum number of calls on a tree

I was asked this question in an interview and struggled to answer it correctly in the time allotted. Nonetheless, I thought it was an interesting problem, and I hadn't seen it before.
Suppose you have a tree where the root can call (on the phone) each of it's children, when a child receives the call, he can call each of his children, etc. The problem is that each call must be done in a number of rounds, and we need to minimize the number of rounds it takes to make the calls. For example, suppose you have the following tree:
A
/ \
/ \
B D
|
|
C
One solution is for A to call D in round one, A to call B in round two, and B to call C in round three. The optimal solution is for A to call B in round one, and A to call D and B to call C in round two.
Note that A cannot call both B and D in the same round, nor can any node call more than one of its children in the same round. However, multiple nodes with a different parent can call simultaneously. For example, given the tree:
A
/ | \
/ | \
B C D
/\ |
/ \ |
E F G
We can have a sequence (where - separates rounds), such as:
A B - B E, A D - B F, A C, D G
(A calls B first round, B calls E and A calls D second, ...)
I'm assuming some type of dynamic programming can be used, but I'm not sure which direction to take this in. My initial inclination is to use DFS to order the longest path from the root to leaves in decreasing order, but when it comes to the nodes actually making calls, I'm not sure how we can achieve optimality given any tree, not how we can output the paths that the optimal calls would make (i.e. in the first example we could output
A B - B C, A D
I think something like this could get the optimal solution:
suppose the value of 'calls' for each of leaves is 1
for each node get the value of calls for all of his children and rank them according to their 'calls' value
consider rank of each child as 'ranks'
to compute the value of 'calls' for each node loop over his children (after computing their ranks) and find the maximum value of 'calls' + 'ranks'
'calls' value of the root node is the answer
It's sorta dynamic programming on trees and you can implement it recursively like this:
int f(node v)
{
int s = 0;
for each u in v.children
{
d[u] = f(u)
}
sort d and rank its values in r (r for the maximum u would be 1)
for each u in v.children
{
s = max(s, d[u] + r[u] + 1)
}
return s
}
Good Luck!

Algorithm(s) / approach

Recently I came across this question and I have no clue where or how to start solving it. Here is the question:
There are 8 statues 0,1,2,3,4,5,6,7 . Each statue is pointing in one of the following four direction North, South, East or West. John would like to arrange the statues so that they all point in same direction. However John is restricted to the following 8 moves which correspond to rotation each statue listed 90 degrees clockwise. (N to E, E to S, S to W, W to N)
Moves
A: 0,1
B: 0,1,2
C: 1,4,5,6
D: 2,5
E: 3,5
F: 3,7
G: 5,7
H: 6,7
Help John figure out fewest number of moves to help point all statues in one direction.
Input : A string initialpos consisting of 8 chars. Each char is either 'N,'S,'E,'W'
Output: An integer which represents fewest no. of moves needed to arrange statues in same direction. If no sequence possible then return -1.
Sample test cases:
input: SSSSSSSS
Output: 0
Explanation: All statues point in same direction. So it takes 0 moves
Test case 1:
Input : WWNNNNNN
Output: 1
Exp: John can use Move A which will make all statues point to North
Test Case 3:
input: NNSEWSWN
Output: 6
Exp: John uses Move A twice, B once, F twice, G once. This will result in all statues facing W.
The only approach I was able to think of was to brute force it. But since the moves can be done multiple times (test case 3), what would be the limit to applying the moves before we conclude that such an arrangement is not possible (i.e output -1)? I am looking for specific types of algorithms that can be used to solve this, also what part of the problem is used in identifying an algorithm.
Note that the order of moves makes no difference, only the set (with repetition). Also note that making the same move 4 times is equivalent to doing nothing, so there is never any reason to make the same move more than 3 times. This reduces the space to 48 possible sequences, which isn't too terrible, but we can still do better than brute force.
The only move that treats 0 and 1 differently is C, so apply C as many times as is necessary to bring 0 and 1 into alignment. We mustn't use C any more than that, and C is the only thing that can move 4, so the remaining task is to align everything to 4.
The only way to move 6 is with H; apply H to align 6.
Now to align 3 and 7. We could do it with E and G, but we may have the option to use F as a short-cut. The optimal number of F moves is not yet clear, so we'll use E and G, and come back to F later.
Apply D to align 5.
Apply B to align 2.
Apply A to align 0 and 1.
Now revisit F, and see whether the short-cut actually saves moves. Pick the optimal number of F moves. (This is easy even by brute force, since there are only 4 possibilities to test.)
The directions N, E, W, S with operation of turning are congruent with Z mod 4 with succ: turn N = (succ 0) mod 4, turn W twice = (succ succ 2) mod 4 etc.
Each move is a vector of zeros (no change) and ones (turn by one) being added to inputs: say you have your example of NNSEWSWN, which would be [0, 0, 2, 1, 3, 2, 3, 0], and you push the button A, which is [1, 1, 0, 0, 0, 0, 0, 0], resulting in [1, 1, 2, 1, 3, 2, 3, 0], or EESEWSWN.
Now if you do a bunch of different operations, they all add up. Thus, you can represent the whole system with this matrix equation:
(start + move_matrix * applied_moves) mod 4 = finish
where start and finish are position vectors as described above, move_matrix the 8x8 matrix with all the moves, and applied_moves a 8-element vector saying how many times we push each button (in range 0..3).
From this, you can get:
applied_moves = (inverse(move_matrix) * (finish - start)) mod 4
Number of applied moves is then just this:
num_applied_moves = sum((inverse(move_matrix) * (finish - start)) mod 4)
Now just plug in the four different values for finish and see which one is least.
You can use matlab, numpy, octave, APL, whatever rocks your boat, as long as it supports matrix algebra, to get your answer very quickly and very easily.
This sounds a little like homework... but I would go with this line of logic.
Run a loop seeing how many moves it would take to move all the statues to face one direction. You would get something like allEast = 30, allWest = 5, etc. Take the lowest sum and corresponding direction would be the answer. With that mindset its pretty easy to build an algorithm to handle computation.
Brute-force could work. A move applied 4 times is the same as not applying the move at all, so each move can only be applied 0, 1, 2, or 3 times.
The order of the moves does not matter. Move a followed by b is the same as b followed by a.
So there are only 4^8 = 65536 possible combinations of moves.
A general solution is to note that there are only 4^8 = 64k different configurations. Each move can therefore be represented as a table of 64k 2 byte indices taking one configuration to the next. The 2 bytes e.g. are divided into 8 2-bit fields 0=N, 1=E, 2=S, 3=W. Further we can use one more table of bits to say which of the 64k configurations have all statues pointing in the same direction.
These tables don't need to be computed at run time. They can be preprocessed while writing the program and stored.
Let table A[c] give the configuration resulting after applying move A to configuration c. and Z[c] return true iff c is a successful config.
So we can use a kind of BFS:
1. Let C be a set of configurations, initially C = { s } where s is the starting config
2. Let n = 0
3. If Z[c] is true for any c in C, return n
4. Let C' be the result of applying A, B, ... H to each element of C.
5. Set C = C', n = n + 1 and go to 3
C can theoretically grow to be almost 64k in size, but the bigger it gets, the better the chances of success, so this ought to be quite fast in practice.

Lazily Tying the Knot for 1 Dimensional Dynamic Programming

Several years ago I took an algorithms course where we were giving the following problem (or one like it):
There is a building of n floors with an elevator that can only go up 2 floors at a time and down 3 floors at a time. Using dynamic programming write a function that will compute the number of steps it takes the elevator to get from floor i to floor j.
This is obviously easy using a stateful approach, you create an array n elements long and fill it up with the values. You could even use a technically non-stateful approach that involves accumulating a result as recursively passing it around. My question is how to do this in a non-stateful manner by using lazy evaluation and tying the knot.
I think I've devised the correct mathematical formula:
where i+2 and i-3 are within the allowed values.
Unfortunately I can't get it to terminate. If I put the i+2 case first and then choose an even floor I can get it to evaluate the even floors below the target level but that's it. I suspect that it shoots straight to the highest even floor for everything else, drops 3 levels, then repeats, forever oscillating between the top few floors.
So it's probably exploring the infinite space (or finite but with loops) in a depth first manner. I can't think of how to explore the space in a breadth first fashion without using a whole lot of data structures in between that effectively mimic a stateful approach.
Although this simple problem is disappointingly difficult I suspect that having seen a solution in 1 dimension I might be able to make it work for a 2 dimensional variation of the problem.
EDIT: A lot of the answers tried to solve the problem in a different way. The problem itself isn't interesting to me, the question is about the method used. Chaosmatter's approach of creating a minimal function which can compare potentially infinite numbers is possibly a step in the right direction. Unfortunately if I try to create a list representing a building with 100 floors the result takes too long to compute, since the solutions to sub problems are not reused.
I made an attempt to use a self-referencing data structure but it doesn't terminate, there is some kind of infinite loop going on. I'll post my code so you can understand what it is I'm going for. I'll change the accepted answer if someone can actually solve the problem using dynamic programming on a self-referential data structure using laziness to avoid computing things more than once.
levels = go [0..10]
where
go [] = []
go (x:xs) = minimum
[ if i == 7
then 0
else 1 + levels !! i
| i <- filter (\n -> n >= 0 && n <= 10) [x+2,x-3] ]
: go xs
You can see how 1 + levels !! i tries to reference the previously calculated result and how filter (\n -> n >= 0 && n <= 10) [x+2,x-3] tries to limit the values of i to valid ones. As I said, this doesn't actually work, it simply demonstrates the method by which I want to see this problem solved. Other ways of solving it are not interesting to me.
Since you're trying to solve this in two dimensions, and for other problems than the one described, let's explore some more general solutions. We are trying to solve the shortest path problem on directed graphs.
Our representation of a graph is currently something like a -> [a], where the function returns the vertices reachable from the input. Any implementation will additionally require that we can compare to see if two vertices are the same, so we'll need Eq a.
The following graph is problematic, and introduces almost all of the difficulty in solving the problem in general:
problematic 1 = [2]
problematic 2 = [3]
problematic 3 = [2]
problematic 4 = []
When trying to reach 4 from 1, there are is a cycle involving 2 and 3 that must be detected to determine that there is no path from 1 to 4.
Breadth-first search
The algorithm Will presented has, if applied to the general problem for finite graphs, worst case performance that is unbounded in both time and space. We can modify his solution to attack the general problem for graphs containing only finite paths and finite cycles by adding cycle detection. Both his original solution and this modification will find finite paths even in infinite graphs, but neither is able to reliably determine that there is no path between two vertices in an infinite graph.
acyclicPaths :: (Eq a) => (a->[a]) -> a -> a -> [[a]]
acyclicPaths steps i j = map (tail . reverse) . filter ((== j).head) $ queue
where
queue = [[i]] ++ gen 1 queue
gen d _ | d <= 0 = []
gen d (visited:t) = let r = filter ((flip notElem) visited) . steps . head $ visited
in map (:visited) r ++ gen (d+length r-1) t
shortestPath :: (Eq a) => (a->[a]) -> a -> a -> Maybe [a]
shortestPath succs i j = listToMaybe (acyclicPaths succs i j)
Reusing the step function from Will's answer as the definition of your example problem, we could get the length of the shortest path from floor 4 to 5 of an 11 story building by fmap length $ shortestPath (step 11) 4 5. This returns Just 3.
Let's consider a finite graph with v vertices and e edges. A graph with v vertices and e edges can be described by an input of size n ~ O(v+e). The worst case graph for this algorithm is to have one unreachable vertex, j, and the remaining vertexes and edges devoted to creating the largest number of acyclic paths starting at i. This is probably something like a clique containing all the vertices that aren't i or j, with edges from i to every other vertex that isn't j. The number of vertices in a clique with e edges is O(e^(1/2)), so this graph has e ~ O(n), v ~ O(n^(1/2)). This graph would have O((n^(1/2))!) paths to explore before determining that j is unreachable.
The memory required by this function for this case is O((n^(1/2))!), since it only requires a constant increase in the queue for each path.
The time required by this function for this case is O((n^(1/2))! * n^(1/2)). Each time it expands a path, it must check that the new node isn't already in the path, which takes O(v) ~ O(n^(1/2)) time. This could be improved to O(log (n^(1/2))) if we had Ord a and used a Set a or similar structure to store the visited vertices.
For non-finite graphs, this function should only fail to terminate exactly when there doesn't exists a finite path from i to j but there does exist a non-finite path from i to j.
Dynamic Programming
A dynamic programming solution doesn't generalize in the same way; let's explore why.
To start with, we'll adapt chaosmasttter's solution to have the same interface as our breadth-first search solution:
instance Show Natural where
show = show . toNum
infinity = Next infinity
shortestPath' :: (Eq a) => (a->[a]) -> a -> a -> Natural
shortestPath' steps i j = go i
where
go i | i == j = Zero
| otherwise = Next . foldr minimal infinity . map go . steps $ i
This works nicely for the elevator problem, shortestPath' (step 11) 4 5 is 3. Unfortunately, for our problematic problem, shortestPath' problematic 1 4 overflows the stack. If we add a bit more code for Natural numbers:
fromInt :: Int -> Natural
fromInt x = (iterate Next Zero) !! x
instance Eq Natural where
Zero == Zero = True
(Next a) == (Next b) = a == b
_ == _ = False
instance Ord Natural where
compare Zero Zero = EQ
compare Zero _ = LT
compare _ Zero = GT
compare (Next a) (Next b) = compare a b
we can ask if the shortest path is shorter than some upper bound. In my opinion, this really shows off what's happening with lazy evaluation. problematic 1 4 < fromInt 100 is False and problematic 1 4 > fromInt 100 is True.
Next, to explore dynamic programming, we'll need to introduce some dynamic programming. Since we will build a table of the solutions to all of the sub-problems, we will need to know the possible values that the vertices can take. This gives us a slightly different interface:
shortestPath'' :: (Ix a) => (a->[a]) -> (a, a) -> a -> a -> Natural
shortestPath'' steps bounds i j = go i
where
go i = lookupTable ! i
lookupTable = buildTable bounds go2
go2 i | i == j = Zero
| otherwise = Next . foldr minimal infinity . map go . steps $ i
-- A utility function that makes memoizing things easier
buildTable :: (Ix i) => (i, i) -> (i -> e) -> Array i e
buildTable bounds f = array bounds . map (\x -> (x, f x)) $ range bounds
We can use this like shortestPath'' (step 11) (1,11) 4 5 or shortestPath'' problematic (1,4) 1 4 < fromInt 100. This still can't detect cycles...
Dynamic programming and cycle detection
The cycle detection is problematic for dynamic programming, because the sub-problems aren't the same when they are approached from different paths. Consider a variant of our problematic problem.
problematic' 1 = [2, 3]
problematic' 2 = [3]
problematic' 3 = [2]
problematic' 4 = []
If we are trying to get from 1 to 4, we have two options:
go to 2 and take the shortest path from 2 to 4
go to 3 and take the shortest path from 3 to 4
If we choose to explore 2, we will be faced with the following option:
go to 3 and take the shortest path from 3 to 4
We want to combine the two explorations of the shortest path from 3 to 4 into the same entry in the table. If we want to avoid cycles, this is really something slightly more subtle. The problems we faced were really:
go to 2 and take the shortest path from 2 to 4 that doesn't visit 1
go to 3 and take the shortest path from 3 to 4 that doesn't visit 1
After choosing 2
go to 3 and take the shortest path from 3 to 4 that doesn't visit 1 or 2
These two questions about how to get from 3 to 4 have two slightly different answers. They are two different sub-problems which can't fit in the same spot in a table. Answering the first question eventually requires determining that you can't get to 4 from 2. Answering the second question is straightforward.
We could make a bunch of tables for each possible set of previously visited vertices, but that doesn't sound very efficient. I've almost convinced myself that we can't do reach-ability as a dynamic programming problem using only laziness.
Breadth-first search redux
While working on a dynamic programming solution with reach-ability or cycle detection, I realized that once we have seen a node in the options, no later path visiting that node can ever be optimal, whether or not we follow that node. If we reconsider problematic':
If we are trying to get from 1 to 4, we have two options:
go to 2 and take the shortest path from 2 to 4 without visiting 1, 2, or 3
go to 3 and take the shortest path from 3 to 4 without visiting 1, 2, or 3
This gives us an algorithm to find the length of the shortest path quite easily:
-- Vertices first reachable in each generation
generations :: (Ord a) => (a->[a]) -> a -> [Set.Set a]
generations steps i = takeWhile (not . Set.null) $ Set.singleton i: go (Set.singleton i) (Set.singleton i)
where go seen previouslyNovel = let reachable = Set.fromList (Set.toList previouslyNovel >>= steps)
novel = reachable `Set.difference` seen
nowSeen = reachable `Set.union` seen
in novel:go nowSeen novel
lengthShortestPath :: (Ord a) => (a->[a]) -> a -> a -> Maybe Int
lengthShortestPath steps i j = findIndex (Set.member j) $ generations steps i
As expected, lengthShortestPath (step 11) 4 5 is Just 3 and lengthShortestPath problematic 1 4 is Nothing.
In the worst case, generations requires space that is O(v*log v), and time that is O(v*e*log v).
The problem is that min needs to fully evaluate both calls to f,
so if one of them loops infinitly min will never return.
So you have to create a new type, encoding that the number returned by f is Zero or a Successor of Zero.
data Natural = Next Natural
| Zero
toNum :: Num n => Natural -> n
toNum Zero = 0
toNum (Next n) = 1 + (toNum n)
minimal :: Natural -> Natural -> Natural
minimal Zero _ = Zero
minimal _ Zero = Zero
minimal (Next a) (Next b) = Next $ minimal a b
f i j | i == j = Zero
| otherwise = Next $ minimal (f l j) (f r j)
where l = i + 2
r = i - 3
This code actually works.
standing on the floor i of n-story building, find minimal number of steps it takes to get to the floor j, where
step n i = [i-3 | i-3 > 0] ++ [i+2 | i+2 <= n]
thus we have a tree. we need to search it in breadth-first fashion until we get a node holding the value j. its depth is the number of steps. we build a queue, carrying the depth levels,
solution n i j = case dropWhile ((/= j).snd) queue
of [] -> Nothing
((k,_):_) -> Just k
where
queue = [(0,i)] ++ gen 1 queue
The function gen d p takes its input p from d notches back from its production point along the output queue:
gen d _ | d <= 0 = []
gen d ((k,i1):t) = let r = step n i1
in map (k+1 ,) r ++ gen (d+length r-1) t
Uses TupleSections. There's no knot tying here, just corecursion, i.e. (optimistic) forward production and frugal exploration. Works fine without knot tying because we only look for the first solution. If we were searching for several of them, then we'd need to eliminate the cycles somehow.
see also: https://en.wikipedia.org/wiki/Corecursion#Discussion
With the cycle detection:
solutionCD1 n i j = case dropWhile ((/= j).snd) queue
of [] -> Nothing
((k,_):_) -> Just k
where
step n i visited = [i2 | let i2=i-3, not $ elem i2 visited, i2 > 0]
++ [i2 | let i2=i+2, not $ elem i2 visited, i2 <=n]
queue = [(0,i)] ++ gen 1 queue [i]
gen d _ _ | d <= 0 = []
gen d ((k,i1):t) visited = let r = step n i1 visited
in map (k+1 ,) r ++
gen (d+length r-1) t (r++visited)
e.g. solution CD1 100 100 7 runs instantly, producing Just 31. The visited list is pretty much a copy of the instantiated prefix of the queue itself. It could be maintained as a Map, to improve time complexity (as it is, sol 10000 10000 7 => Just 3331 takes 1.27 secs on Ideone).
Some explanations seem to be in order.
First, there's nothing 2D about your problem, because the target floor j is fixed.
What you seem to want is memoization, as your latest edit indicates. Memoization is useful for recursive solutions; your function is indeed recursive - analyzing its argument into sub-cases, synthetizing its result from results of calling itself on sub-cases (here, i+2 and i-3) which are closer to the base case (here, i==j).
Because arithmetics is strict, your formula is divergent in the presence of any infinite path in the tree of steps (going from floor to floor). The answer by chaosmasttter, by using lazy arithmetics instead, turns it automagically into a breadth-first search algorithm which is divergent only if there's no finite paths in the tree, exactly like my first solution above (save for the fact that it's not checking for out-of-bounds indices). But it is still recursive, so indeed memoization is called for.
The usual way to approach it first, is to introduce sharing by "going through a list" (inefficient, because of sequential access; for efficient memoization solutions see hackage):
f n i j = g i
where
gs = map g [0..n] -- floors 1,...,n (0 is unused)
g i | i == j = Zero
| r > n = Next (gs !! l) -- assuming there's enough floors in the building
| l < 1 = Next (gs !! r)
| otherwise = Next $ minimal (gs !! l) (gs !! r)
where r = i + 2
l = i - 3
not tested.
My solution is corecursive. It needs no memoization (just needs to be careful with the duplicates), because it is generative, like the dynamic programming is too. It proceeds away from its starting case, i.e. the starting floor. An external accessor chooses the appropriate generated result.
It does tie a knot - it defines queue by using it - queue is on both sides of the equation. I consider it the simpler case of knot tying, because it is just about accessing the previously generated values, in disguise.
The knot tying of the 2nd kind, the more complicated one, is usually about putting some yet-undefined value in some data structure and returning it to be defined by some later portion of the code (like e.g. a back-link pointer in doubly-linked circular list); this is indeed not what my1 code is doing. What it does do is generating a queue, adding at its end and "removing" from its front; in the end it's just a difference list technique of Prolog, the open-ended list with its end pointer maintained and updated, the top-down list building of tail recursion modulo cons - all the same things conceptually. First described (though not named) in 1974, AFAIK.
1 based entirely on the code from Wikipedia.
Others have answered your direct question about dynamic programming. However, for this kind of problem I think the greedy approach works the best. It's implementation is very straightforward.
f i j :: Int -> Int -> Int
f i j = snd $ until (\(i,_) -> i == j)
(\(i,x) -> (i + if i < j then 2 else (-3),x+1))
(i,0)

Fewer moves to chessboard edge

Today in an exam I was given a algorithmic problem where I was given the size N*M of a chessboard, and I should determine what is the smallest possible number of moves that a knight can do from the bottom left edge of the chessboard to go to the up right edge. How can that be done?
A solution using BFS and memoization:
# Memoization
memo = a matrix of NOVISITED of size N x M
# Starting position
# (row, column, jumps)
queue.push((0, 0, 0))
while queue is not empty:
# Get next not visited position
row, column, jumps = queue.pop()
# Mark as visited
memo[row][column] = jumps
for each possible move (nrow, ncolumn) from (row, column):
if memo[nrow][ncolumn] is NOVISITED:
# Queue next possible move
queue.append((nrow, ncolumn, jumps + 1))
NOVISITED can have value -1 or null if we consider the possible distances as a non-negative number [0,+inf).
The minimum number of jumps for each square will be accesible in memo[row][column], so the answer for the top-right corner from the bottom-left will be at memo[N - 1][M - 1].
UPDATE
Notice that if the matrix is square N x N, you can apply symmetry principles.
I believe you can reduce this down to three cases:
You have a board with no solution example: 2w * 4h
You have a board with a solution of 1: 2w * 3h
You have a board that is square and thus has a solution of 4: 3w * 3h
If you have a board larger than these, you can reduce it to one of them by setting the endpoint of one move as the starting point of a larger board.
Example: a board of size 4w * 5h:
_ _ _ _
_ _ _ _
_ e _ _
_ _ _ _
s _ _ _
where s is start and e is end.
From there, reduce it to a square board:
_ 1 e
3 _ _
s _ 2
Where it takes 4 moves to reach the end. So you have 1 + 4 moves = 5 for this size.
I hope that is enough to get you started.
EDIT: This doesn't seem to be perfect as is. However, it demonstrates a heuristic way to solve this problem. Here is another case for your viewing pleasure:
_ _ _ e
_ 3 _ _
_ _ _ _
_ _ 2 _
_ _ _ _
_ 1 _ _
_ _ _ _
s _ _ _
that has 4 moves until the end in a 4x8 board.
Via a programming lanugage, this might be better solved by starting out by mapping all possible moves from your current location and seeing if they match the end point. If they don't, check to see if your problem is now a simpler one that you have solved before. This is accomplished via memoization, as a commenter pointed out.
If you are doing this by hand, however, I bet you can solve it by isolating it into a small number of cases as I have begun to do.
You could simulate the knight's move using BFS or DFS. Personally I prefer the DFS approach, as it can be implemended recursively. If you have a function process which takes as parameters the current x position, the current y position, the rows of the table, the columns of the table and a counter, the the solution will look like that:
/* .......... */
process(x-1, y-2, R, C, count+1);
process(x+1, y-2, R, C, count+1);
process(x-2, y-1, R, C, count+1);
process(x-2, y+1, R, C, count+1);
process(x-1, y+2, R, C, count+1);
process(x+1, y+2, R, C, count+1);
process(x+2, y-1, R, C, count+1);
process(x+2, y+1, R, C, count+1);
/* .......... */
When you reach your destination, you return the current value of count.
EDIT: it can also be solved using dynamic programming. You define dp(i,j) to be the best way to reach the square (i,j). So dp(i,j) is equal to:
dp(i,j) = min{dp(all squares that can reach (i,j) in one move)} + 1
Here is the efficient solution.
First, special cases. If n = 1 you cannot jump, and the problem is only solvable for (1, 1). If n = 2 by inspection there is only one path you can take, and the problem is only solvable if m = 4k + 3 in which case you need 2k + 1 jumps to get there. The reverse is true if m = 1,2.
Now the general case. A knight has 8 possible jumps, it goes 2 in one direction, and then 1 in another. The possible directions are r, l, u, d (right, left, up, down). So let nru be the number of times it jumps 2 right, then 1 up, and likewise for the other 7 possible jumps. Then the answer must be a solution to the following pair of equations:
n - 1 = 2*nru + nur - nul - 2*nlu - 2*nld - ndl + ndr + 2*nrd
m - 1 = nru + 2*nur + 2*nul + nlu - nld - 2*ndl - 2*ndr - nrd
And the number of jumps is:
nru + nur + nul + nlu + nld + ndl + ndr + nrd
We expect the number of jumps to be as low as possible. Intuitively if we have a set of numbers that satisfies the top two equations, and we've made the number of jumps low, we shouldn't have much trouble in finding an order to put the jumps which stays inside of the box. I won't prove it, but this turns out to be true if 2 < n and 2 < m.
Thus solve this integer programming problem (solve those two equations keeping the number of jumps as low as possible) and we have our answer. There are solvers for this, but this particular problem is very simple. We just do the "obvious thing" to get close to our target, figure out a couple of extra jumps, and it is not hard to prove that this is an optimal solution to the integer equations, and therefore must be the answer to the chess problem.
So what is the obvious thing? First, if m < n, we can just flip the board over, so without loss of generality we may assume that n < m. (The board goes at least as far from you as it does sideways.) Given that fact, the obvious thing is to jump up-left until you hit the wall, or you hit the diagonal stretching down from the corner that you want. At which point you progress along the wall or that diagonal towards your target.
If you land directly on the target, you have your best possible answer.
If you went along the wall and missed by 1, it turns out that by converting one of your jumps into a pair you wind up where you need to be. If you went along the wall and missed by 2 (ie you're one diagonal) then you need to insert 2 jumps. (Distance shows you that you need at least one more, and a simple parity argument shows that you need at least 2, and a pair of jumps will do it.)
If you went along the diagonal and missed by 1, insert one pair of jumps and you're good.
If you went along the diagonal and missed by 2, then convert a up-right/right-up pair into right-up/right-up/up-left/left-up and you can do it with just 2 more jumps.
If you did not travel along the diagonal but had a up-left, convert that into a right-up/up-left/right-up triplet and again you can do it with just 2 more jumps.
The remaining special case is a 3x3 board, which takes 4 jumps.
(I leave it to you to figure out all of the appropriate inequalities and modulos that picture works out to.)

Code Golf: Towers of Hanoi

Locked. This question and its answers are locked because the question is off-topic but has historical significance. It is not currently accepting new answers or interactions.
Rules
The Towers of Hanoi is a puzzle, and if you are not very familiar with it, here is how it works:
The play field consists of 3 rods, and x number of disks, each next one bigger than the previous one. The disks can be put on the rod, with these RULES:
only one disk can be moved at once, and it must be moved on the top of another rod
the disk must be taken from the top of a rod
a disk can be moved somewhere, ONLY if the top-most disk at the target rod is bigger than the one to be moved
And finally - the play field STARTS like this:
a rod, with x disks, sorted so the largest is on the bottom, and the smallest on the top
an empty rod
an empty rod
The GOAL of the game is to move the original "stack" of disks on another rod, that is - put all of the disks on another rod, so (again) the largest is on the bottom, and the smallest on the top
Implementation
YOUR goal will be to make a program in programming language of your choice, that takes an input (described below) and outputs the steps necessary to solve the position.
As always, try to make it as short as possible.
Input
An example input:
4-3,7-6-5,2-1
Input is a string, consisting of 3 parts, separated by commas. The parts are a list of disks on each of the 3 rods. They are separated too, this time with hyphens ( - ), and each subpart is a number, the larger the number is, the larger the disk is.
So - for the above input, this would be a visual representation:
. . .
| =====|===== |
===|=== ======|====== =|=
====|==== =======|======= ==|==
ROD 1 ROD 2 ROD 3
Output
As you can see in the above representation - the the left-most part of the input is rod number one, the middle is rod number two, and the last one is rod number 3.
The output of your program should look like this:
12,23,31,12,23,13
A list of numbers, separated by commas that defines the rod that a disk should be taken of, and the rod that the disk should be put on. There are only 3 rods, so there is just 6 possible combinations (because a disk has to be moved to another rod, not the same one):
12
13
21
23
31
32
Notes
The input does not have to describe a field in "original" state - it can be mid-solved.
Your program can NOT produce null output. If the input IS in the original state, just put the disks to a DIFFERENT rod.
The input can have an empty rod(s), like these:
2-1,3,
,,1
4-3,,2-1
If the input is not in this formatted like that, your program can produce undefined behavior. So it can if the input is not valid (like bigger disk on a smaller one, missing disk, unsolvable). Input will always be valid.
Make sure the solution is as fast as possible (as little turns as possible) - that is, don't waste turns by "12,21,12"...
Testing
So, I prepared this small flash for you, with which you can test if your program produced a good solution without writing it down or anything.
Here it is: Hanoi AlgoTest (wait for it to load then refresh -- Dead link :|)
To use it, paste the input to the program to the INPUT field, and the output produced by your program to the PROCESS field. It will run a simulation, at speed which you can also change, with a visual representation, printing out any errors in the bottom part.
Hope it helps.
Perl, 209 (203) char
Rewritten to keep track of the location of each disk as opposed to the list of disks that are contained on each rod.
306 291 263 244
236 213 209 chars after removing unnecessary whitespace.
sub M{my($r,$s)=#_;if(--$m){M($r,$r^$s);$_.=",$r$s";M($r^$s,$s)}s/(.),?\1//;
$R[++$m]=$p}map#R[/\d+/g]=(++$i)x99,split/,/,<>;do{1until
($n=$R[1])-($p=$R[++$m]||$n-1|2);M$n,$p}while 1<grep#R~~$_,1..3;s/^,//;print
$R[j]: the location of disk j
$n: the location of disk #1
$m: the number of disks to move
$p: the location to move the disks to
&M(r,s): move $m-1 disks from r to s. Appends to $_ and sets #R
The substitution inside sub M optimizes the output, removing extraneous steps. It could be removed (12 characters) and the output would still be valid.
Another 12 characters can be removed if the perl interpreter is invoked with the command-line switch -apF,. With the extra 6 chars for the command-line switch, this gets us down to net 203 characters:
# invoke as perl -apF, ...
sub M{my($r,$s)=#_;if(--$m){M($r,$r^$s);$_=$a.=",$r$s";M($r^$s,$s)}
s/(.),\1//;$R[++$m]=$p}map#R[/\d+/g]=(++$i)x99,#F;
do{1until($n=$R[1])-($p=$R[++$m]||$n-1|2);M$n,$p}while 1<grep#R~~$_,1..3;s/^,//
Here's a starter for 10, in Scala, revised a few times. I don't know of any issues, and I have no other ideas for further reducing the moves
Runs as a Scala script.
Bits of this are quite elegant (IMO) but other bits are an ugly hack
Shortest code (but non-optimal moves), tracking position of disks rather than list of disks on rods (idea shamelessly stolen from the Perl solution)
val r=args(0).split(",",-1);var d=Map{{for(q<-0 to 2 if""!=r(q);n<-r(q).split('-').map{_.toInt})yield(n,q+1)}:_*};val n=d.max._1;var m="";def s(f:Int,t:Int,n:Int):Unit=if(n!=0&&f!=t){s(f,6-f-t,n-1);d=d+(n->t);m=m+","+f+t;s(6-f-t,t,n-1)};for(c<- 2 to n)s(d(1),d(c),c-1);if(m=="")s(d(1),d(1)%3+1,n);println(m.tail.replaceAll("(.),?\\1",""))
Puzzle is taken from the command line.
338 bytes. Not too shabby since this is a statically typed language, and still relatively readable (if you replace ; with newlines)
Readable version follows (with more optimal moves)
val rods = args(0).split(",", -1);
var diskLocation = Map{
{
for (rod <-0 to 2 if rods(rod).nonEmpty;
n <-rods(rod).split('-').map{_.toInt})
yield(n, rod + 1)
}:_*
}
val nDisks = diskLocation.max._1
var moves = ""
def moveTower(start:Int, end:Int, n:Int):Unit =
if (n != 0) {
val other = 6 - start - end
moveTower(start, other, n - 1)
moveDisk(n, end)
moveTower(other, end, n - 1)
}
def moveDisk(n:Int, end:Int) = {
moves = moves + "," + diskLocation(n) + end
diskLocation = diskLocation.updated(n, end);
}
for (c <- 2 to nDisks) {
var firstLocation = diskLocation(1)
var nextLocation = diskLocation(c)
if (firstLocation != nextLocation) {
if (c != nDisks) {
val diskAfter = diskLocation(c + 1)
if (diskAfter != firstLocation && diskAfter != nextLocation) {
moveDisk(c, diskAfter)
nextLocation = diskAfter
}
}
moveTower(diskLocation(1), diskLocation(c), c - 1);
}
}
if (moves == "")
moveTower(diskLocation(1), diskLocation(1)%3 + 1, nDisks)
println(moves.tail.replaceAll("(.),?\\1",""))
Perl 241 char
Certainly not the most efficient way, but it works.
Updated to suppress last comma.
map{map$g[$_]=$i|0,/\d/g;$i++}split$,=',',<>;shift#g;#G=(0)x#g;#u=(1)x10;while(!$G[#g]){$G="#G";$_="#g";$i=0;$j=$G[0]+$u[0];while($j>2||$j<0){$u[$i++]*=-1;$j=$u[$i]+$G[$i]}$r=1+$G[$i].$j+1;$G[$i]=$j;$p=1if/$G/;push#o,$r if$p&&$i++<#g}print#o
Same with whitespaces:
map{
map $g[$_]=$i|0, /\d/g;
$i++
}split$,=',',<>;
shift#g;
#G=(0)x#g;
#u=(1)x10;
while(!$G[#g]){
$G="#G";
$_="#g";
$i=0;
$j=$G[0]+$u[0];
while($j>2||$j<0){
$u[$i++]*=-1;
$j=$u[$i]+$G[$i]
}
$r=1+$G[$i].$j+1;
$G[$i]=$j;
$p=1if/$G/;
push#o,$r if$p&&$i++<#g
}
print#o
Usage:
echo 5-2,3-1,4 | perl hanoi.pl
Output:
21,23,12,23,12,32,21,23,12,23,12,32,21,32,12,23,21,32,21,32,12,23,12,32,21,23,12,23,21,32,21,32,12,23,21,32,21,32,12,23,12,32,21,23,12,23,12,32,21,32,12,23,21,32,21,23,12,23,12,32,21,23,12,23,21,32,21,32,12,23,21,32,21,32,12,23,12,32,21,23,12,23,21,32,21,32,12,23,21,32,21,23,12,23,12,32,21,23,12,23,12,32,21,32,12,23,21,32,21,23,12,23,12,32,21,23,12,23,12,32,21,32,12,23,21,32,21,32,12,23,12,32,21,23,12,23,21,32,21,32,12,23,21,32,21,23,12,23,12,32,21,23,12,23,12,32,21,32,12,23,21,32,21,23,12,23,12,32,21,23,12,23
Attempt at Lua
I've tried to implement the iterative solution from wikipedia, but it doesn't really work, but the time i'm spending on it is up, so I hope this inspires someone to adapt it.
It does parse everything well, including empty columns.
Extra goodie: it does pretty printing of the stacks as in the visual representation in the question.
-- Input "rod1,rod2,rod3" where rod? = a - seperated list of numbers, representing the disks.
p,q,r=io.read():match'([^,]*),([^,]*),([^,]*)'
print(p,q,r)
i=table.insert
u=unpack
function gen(t)
return function(v)i(t,tonumber(v)) end
end
function basic(t,n)
for k,v in pairs(t) do
print(k,"----")
for kk,vv in pairs(v) do print("\t",kk,vv) end
end
print'================'
end
function pretty(t,n)
local out={}
for k=1,n do out[k]={} end
for k=1,n do -- K is each row
local line=out[k]
for l=1,3 do -- L is each rod
local d=t[l][k]
if d~=1e9 then -- TODO Check if metahack necesarry
line[#line+1]=(" "):rep(n-d+1)
line[#line+1]=("="):rep(d)
line[#line+1]="|"
line[#line+1]=("="):rep(d)
line[#line+1]=(" "):rep(n-d+1)
line[#line+1]=" "
else
line[#line+1]=(" "):rep(2*n+4)
end
end
out[k]=table.concat(line)
end
for k=n,1,-1 do
io.write(out[k],"\n")
end
end
function T(f,...)
w=0
for k=1,3 do
l=({...})[k]
w=#l==0 and w or f(w,u(l))
end
return w
end
Stat=pretty
t={{},{},{}} --rods 1 - 3, discs ordered 1 = bottom
for k,v in pairs{p,q,r}do -- loop over strings
v:gsub('%d+',gen(t[k])) -- add decimal to rod
end
n=T(math.max,t[1],t[2],t[3]) -- Biggest disc = number of discs
--for k=1,3 do c=1*t[k][1] if n==c then A=k elseif m==c then C=k else B=k end end -- Rod where the biggest disc is (A)
for k=1,3 do setmetatable(t[k],{__index = function() return 1e9 end}) c=t[k] if c[#c]==1 then one=k end end -- locate smallest disc, and set index for nonexistant discs to 1e9
-- Locate second biggest disc (B), smallest stack = C -> move C to B
-- Algorithm:
-- uneven : move to the left, even: move to the right
-- move smallest, then move non-smallest.
-- repeat until done
--
-- For an even number of disks:
--
-- * make the legal move between pegs A and B
-- * make the legal move between pegs A and C
-- * make the legal move between pegs B and C
-- * repeat until complete
--
-- For an odd number of disks:
--
-- * make the legal move between pegs A and C
-- * make the legal move between pegs A and B
-- * make the legal move between pegs B and C
-- * repeat until complete
--
-- In each case, a total of 2n-1 moves are made.
d={{2,3,1},{3,1,2}}
s=d[math.fmod(n,2)+1] -- sense of movement -1 left (uneven # of discs), 1 right (even # of discs)
Stat(t,n)
for qqq=1,10 do
-- move smallest
d=s[one]
print(one,d)
if #t[d]==0 then print("skip rod",d,"next rod",s[d]) d=s[d] end-- if rod is empty, move to next in same direction
table.insert(t[d],table.remove(t[one])) --TODO Problem
print("Moved",one,"to",d)
one=d -- track the small disc
Stat(t,n)
if #t[d]==n then break end -- destination stack reached number of discs, break off.
-- find next valid move (compare the two non-previous-destination rod) to see which has the smallest disc, move disc to other rod.
z=0
for k=1,3 do
print("-- k="..k)
if k~=one then
if z>0 then
if t[k][#t[k]] > t[z][#t[z]] then -- disc at rod z (source) is smaller than at k (destination)
d=k -- destination = k
print("-- t["..k.."]>t["..z.."], d="..d..", z="..z)
else -- disc at rod z (source) is bigger than at k (destination
d,z=z,k -- switch destination and source, so d will be z, and z will be the current rod
print("-- t["..k.."]<t["..z.."], d="..d..", z="..z)
end
else -- first of rods to compare
z=k
print("-- First rod to compare z="..z)
end
else
print("-- disc one at this location, skipping",k)
end
end
print("Will move from",z,"to",d)
table.insert(t[d],table.remove(t[z]))
Stat(t,n)
if #t[d]==n then break end -- destination stack reached number of discs, break off.
end

Resources