Башни Ханоя с K колышками

Башни Ханоя проблема является классической проблемой для рекурсии. Вам предоставляется 3 колышка с дисками на одном из них, и вы должны переместить все диски с одного колышка на другой, следуя приведенным правилам. Вы также должны сделать это с минимальным количеством ходов.

Вот рекурсивный алгоритм, который решает проблему:

void Hanoi3(int nDisks, char source, char intermed, char dest)
{
    if( nDisks > 0 )
    {
        Hanoi3(nDisks - 1, source, dest, intermed);
        cout << source << " --> " << dest << endl;
        Hanoi3(nDisks - 1, intermed, source, dest);
    }
}


int main()
{
    Hanoi3(3, 'A', 'B', 'C');

    return 0;
}

Теперь представьте себе ту же проблему, только с 4 колышками, поэтому мы добавим еще один промежуточный колышек. Столкнувшись с проблемой необходимости выбора промежуточного колышка в любой точке, мы выберем самый левый, если больше 1 свободно.

У меня есть следующий рекурсивный алгоритм для этой проблемы:

void Hanoi4(int nDisks, char source, char intermed1, char intermed2, char dest)
{
    if ( nDisks == 1 )
        cout << source << " --> " << dest << endl;
    else if ( nDisks == 2 )
    {
        cout << source << " --> " << intermed1 << endl;
        cout << source << " --> " << dest << endl;
        cout << intermed1 << " --> " << dest << endl;
    }
    else
    {
        Hanoi4(nDisks - 2, source, intermed2, dest, intermed1);
        cout << source << " --> " << intermed2 << endl;
        cout << source << " --> " << dest << endl;
        cout << intermed2 << " --> " << dest << endl;
        Hanoi4(nDisks - 2, intermed1, source, intermed2, dest);
    }
}

int main()
{
    Hanoi4(3, 'A', 'B', 'C', 'D');

    return 0;
}

Теперь мой вопрос: как бы я обобщил этот рекурсивный подход к работе дляK колышки? Рекурсивная функция получитchar[] который будет содержать метки каждого стека, поэтому функция будет выглядеть примерно так:

void HanoiK(int nDisks, int kStacks, char labels[]) { ... }

Я знаю об алгоритме Фрейма-Стюарта, который, скорее всего, оптимален, но не доказан, и который дает вамчисло ходов. Тем не менее, меня интересует строго рекурсивное решение, которое следует шаблону рекурсивных решений для 3 и 4 колышков, то есть оно печатает фактические ходы.

По крайней мере, для меня псевдокод алгоритма Фрейма-Стюарта, представленный в Википедии, довольно абстрактный, и мне не удалось перевести его в код, который печатает ходы. Я бы принял эталонную реализацию этого (для случайногоk) или даже более подробный псевдокод.

Я пытался придумать какой-то алгоритм, который соответствующим образом переставляет массив меток, но мне не повезло заставить его работать. Любые предложения приветствуются.

Обновить:

Кажется, что это намного проще решить на функциональном языке. Вот реализация F #, основанная на решении Haskell от LarsH:

let rec HanoiK n pegs = 
    if n > 0 then 
        match pegs with
        | p1::p2::rest when rest.IsEmpty            
            ->  printfn "%A --> %A" p1 p2
        | p1::p2::p3::rest when rest.IsEmpty        
            ->  HanoiK (n-1) (p1::p3::p2::rest)
                printfn "%A --> %A" p1 p2
                HanoiK (n-1) (p3::p2::p1::rest)    
        | p1::p2::p3::rest when not rest.IsEmpty    
            ->  let k = int(n / 2)
                HanoiK k (p1::p3::p2::rest)
                HanoiK (n-k) (p1::p2::rest)
                HanoiK k (p3::p2::p1::rest)

let _ =
    HanoiK 6 [1; 2; 3; 4; 5; 6]

И не рассматривая 3 колышка как крайний случай:

let rec HanoiK n pegs = 
    if n > 0 then 
        match pegs with
        | p1::p2::rest when rest.IsEmpty            
            ->  printfn "%A --> %A" p1 p2
        | p1::p2::p3::rest     
            ->  let k = if rest.IsEmpty then n - 1 else int(n / 2) 
                HanoiK k (p1::p3::p2::rest)
                HanoiK (n-k) (p1::p2::rest)
                HanoiK k (p3::p2::p1::rest)

Обратите внимание, что это не относится к вырожденным случаям, для которых нет решения, таких какHanoiK 2 [1; 2]

Ответы на вопрос(6)

Ваш ответ на вопрос