Конфигурация Ханоя на определенном шаге - PullRequest
7 голосов
/ 05 мая 2011

Мне интересно узнать, сколько дисков на каждом колышке на заданном ходу в головоломке Hanoi .Например, для n = 3 дисков мы имеем следующую последовательность конфигураций для оптимального решения головоломки:

   0 1 2
0. 3 0 0
1. 2 0 1 (move 0 -> 2)
2. 1 1 1 (move 0 -> 1)
3. 1 2 0 (move 2 -> 1)
4. 0 2 1 (move 0 -> 2)
5. 1 1 1 (move 1 -> 0)
6. 1 0 2 (move 1 -> 2)
7. 0 0 3 (move 0 -> 2)

Итак, учитывая ход № 5, я хочу вернуть 1 1 1, учитывая ход № 6, я хочу1 0 2 и т. Д.

Это легко сделать, используя классический алгоритм и останавливая его после определенного числа ходов, но я хочу что-то более эффективное.На странице википедии, на которую я ссылался выше, приведен алгоритм в разделе Binary solutions.Я думаю, что это неправильно, однако.Я также не понимаю, как они вычисляют n.

. Если вы последуете их примеру и сконвертируете позиции дисков, они вернутся к тому, что я хочу, это даст 4 0 4 для n = 8 дисков и номер хода 216.Однако, используя классический алгоритм, я получаю 4 2 2.

. Здесь также есть эффективный алгоритм, реализованный в C , который также дает 4 2 2 в качестве ответа, но ему не хватает документации и яУ меня нет доступа к статье, на которой она основана.

Алгоритм в предыдущей ссылке кажется правильным, но кто-нибудь может объяснить, как именно он работает?

Несколько связанных вопросов, на которые я отвечаютакже интересует:

  1. Действительно ли алгоритм википедии неверен или я что-то упустил?И как они вычисляют n?
  2. Я только хочу знать, сколько дисков находится на каждом штифте в определенный момент, а не на том, на каком штифте находится каждый диск, что в литературе кажется болееобеспокоен.Есть ли более простой способ решить мою проблему?

Ответы [ 3 ]

1 голос
/ 12 мая 2011

Вы можете использовать тот факт, что позиция в степени двух легко известна.Для башни размера T имеем:

Time          Heights
2^T-1      |  {  0,   0,   T }
2^(T-1)    |  {  0, T-1,   1 }
2^(T-1)-1  |  {  1, T-1,   0 }
2^(T-2)    |  {  1,   1, T-2 }
2^(T-2)-1  |  {  2,   0, T-2 }
2^(T-2)    |  {  2, T-3,   1 }
2^(T-2)-1  |  {  3, T-3,   0 }
          ...
0          |  {  T,   0,   0 }

Легко узнать, между какими уровнями находится ваш ход k;просто посмотрите на log2 (k).

Далее, обратите внимание, что между 2 ^ (a-1) и 2 ^ a-1 есть Ta-диски, которые остаются на том же месте (самые тяжелые диски).Однако все остальные блоки будут перемещены, так как на этом этапе алгоритм перемещает подзадачу размера a.Следовательно, используйте итеративный подход.

Может быть немного сложно правильно вести бухгалтерский учет, но здесь у вас есть ингредиенты, чтобы найти высоты для любого k с временной сложностью O (log2 (T)).

Приветствия

1 голос
/ 05 мая 2011

1) Если ваш алгоритм говорит, что Википедия не работает, я думаю, вы правы ...

2) Что касается расчета количества дисков в каждом колышке, достаточно ли просто сделать рекурсивный алгоритм для него:

(непроверенный, нелегальный и, возможно, полный + -1 код ошибки:)

function hanoi(n, nsteps, begin, middle, end, nb, nm, ne)
    // n = number of disks to mive from begin to end
    // nsteps = number of steps to move
    // begin, middle, end = index of the pegs
    // nb, nm, ne = number of disks currently in each of the pegs

    if(nsteps = 0) return (begin, middle, end, nb, nm, ne)

    //else:

    //hanoi goes like
    // a) h(n-1, begin, end, middle) | 2^(n-1) steps
    // b) move 1 from begin -> end   | 1 step
    // c) h(n-1, middle, begin, end) | 2^(n-1) steps
    // Since we know how the pile will look like after a), b) and c)
    // we can skip those steps if nsteps is large...

    if(nsteps <= 2^(n-1)){
        return hanoi(n-1, nsteps, begin, end, middle, nb, ne, nm):
    }
    nb -= n;
    nm += (n-1);
    ne += 1;
    nsteps -= (2^(n-1) + 1);
    //we are now between b) and c)

    return hanoi((n-1), nsteps, middle, begin, end, nm, nb, ne);

function(h, n, nsteps)
    return hanoi(n, nsteps, 1, 2, 3, n, 0, 0)

Если вам нужна эффективность, он должен попытаться преобразовать это в итеративную форму (не должно быть сложно - вам не нужно все равно хранить стек) и найти способ лучше представить состояние программы, вместо этого использования 6+ переменных Вилли Нилли.

0 голосов
/ 08 ноября 2012
If you look at the first few moves of the puzzle, you'll see an important pattern. Each move (i - j) below means on turn i, move disc j. Discs are 0-indexed, where 0 is the smallest disc.

1 - 0
2 - 1
3 - 0
4 - 2
5 - 0
6 - 1
7 - 0
8 - 3
9 - 0
10 - 1
11 - 0
12 - 2
13 - 0
14 - 1
15 - 0

Диск 0 перемещается каждые 2 оборота, начиная с первого хода. Диск 1 перемещается каждые 4 оборота, начиная с второго хода ... Диск i перемещается каждые 2 ^ (i + 1) оборота, начиная с второго хода ^ я.

Итак, в постоянное время мы можем определить, сколько раз данный диск переместился, учитывая m:

ходов = (m + 2 ^ i) / (2 ^ (i + 1)) [целочисленное деление]

Следующее, что следует отметить, - это то, что каждый диск движется циклически. А именно, диски с нечетными номерами перемещаются влево при каждом перемещении (2, 3, 1, 2, 3, 1 ...), а диски с четными номерами перемещаются вправо (1, 3, 2, 1, 3, 2 ...)

Таким образом, когда вы знаете, сколько раз диск перемещался, вы можете легко определить, на каком колышке он заканчивается, взяв мод 3 (и немного поработав).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...