Обмін стеками


23

Проблема

Скажімо, у вас N стеків, названих від S 1 до S N , де кожен S k (k = 1 до N) містить N копій числа k.

Наприклад, коли N = 3 стеки виглядають так:

1  2  3  <- top of stack
1  2  3
1  2  3  <- bottom of stack
=======
1  2  3  <- stack index

Тут є 3 стеки, індексовані як 1, 2 і 3, і кожен містить N екземплярів власного індексу.

Мета полягає в тому, щоб переставити N стеків таким чином, щоб кожен з них однаково містив числа від 1 до N в порядку зверху вниз.

наприклад, для N = 3 метою є переставити стеки в:

1  1  1
2  2  2
3  3  3
=======
1  2  3

Єдина дія, яку ви можете виконати зі стеками, - це взяти верхній номер з однієї з стеків (вискакувати), а потім негайно поставити його на інший стек (штовхаючи) . Це стосується цих положень:

  • Число може бути висунуте на стек лише у тому випадку, якщо воно менше або дорівнює верхньому номеру в цій стеці.

    • наприклад, a 1може бути висунуто на стек з a 1, 2або 3вгорі, але a 2може бути висунуте на стек лише з a 2або 3(або вище) вгорі.

    • Це призводить до того, що стеки завжди монотонно збільшуються зверху вниз.

  • Будь-який непустий стек може вискочити з, і, якщо попередня куля задоволена, будь-який стек може бути висунутий на.

  • Будь-яке число може бути висунуте на порожній стек.

  • У штабелів немає максимальної межі висоти.

  • Стеки неможливо створити або знищити, їх завжди є N.

Ця задача полягає в тому, щоб визначити, що з'являється та штовхає зробити для того, щоб завершити обмін стеками, не обов'язково за найменші ходи, але надійним способом.

(Тренуватися з колодою карт - хороший спосіб відчути проблему.)

Виклик

Напишіть програму або функцію, яка має додатне ціле число N, гарантовано рівне 3 або вище. Роздрукуйте або поверніть рядок, який позначає всі дії поп-push, необхідні для перестановки стеків у початковий стан:

1  2  3  4  5
1  2  3  4  5
1  2  3  4  5
1  2  3  4  5
1  2  3  4  5
=============
1  2  3  4  5

(N = 5 випадків)

До остаточного стану:

1  1  1  1  1
2  2  2  2  2
3  3  3  3  3
4  4  4  4  4
5  5  5  5  5
=============
1  2  3  4  5

Кожен рядок у вашому висновку повинен містити два числа, розділені пробілом. Перше число - це індекс стека, на який слід випливати, а друге число - індекс стека, на який потрібно натиснути. Виконуючи дії всіх рядків в порядку, слід розташовувати стеки правильно, не порушуючи жодних правил.

Наприклад, ось потенційний дійсний вихід для випадку N = 3:

1 2  [move the top number on stack 1 to the top of stack 2]
1 2  [repeat]
1 2  [repeat]
3 1  [move the top number on stack 3 to the top of stack 1]
2 3  [etc.]
2 3
2 3
2 1
2 1
2 1
3 1
3 1
3 1
3 2
1 2
1 2
1 2
1 3
2 3
2 3
2 3
1 2
3 2
3 1

Примітки

  • Ваш результат не повинен бути оптимальним , а лише правильним. тобто вам не потрібно мінімізувати кількість попсів і натискань.

    • Тож було б добре, якби, скажімо, якийсь хід був неодноразово зроблений і негайно відмінений.
    • Вискакування та натискання на одну групу одним ходом, наприклад 2 2, дозволено також (хоча, звичайно, безглуздо).
  • Ваш висновок робить потреба бути детермінованим і кінцевим.

  • Пам'ятайте, що стеки мають індексацію на основі 1. Індексація на основі 0 не дозволена.

  • N більший за 9, звичайно, повинен працювати так само добре, як однозначний N.

  • За бажанням ви можете використовувати будь-які два нецифрові символи для друку ASCII замість пробілів та нових рядків. Зворотний новий рядок (або замінник нового рядка) у виході є нормальним.

Оцінка балів

Виграє найкоротший код у байтах. Tiereaker є вищою відповіді.

Безцінні бали брауні, якщо ви можете показати свій алгоритм, є оптимальним.


Зупиніться на дурниці "додаткові бали за дрібниці"> _>
user48538

18
@ zyabin101 Ви просто втратили будь-який шанс на брауні.
Хобі Кальвіна

9
Ви завжди придумуєте такі чудові назви!
Луїс Мендо

@HelkaHomba-._(._.)_.-
user48538

Чи можливий вихід, який ви включаєте для N=3оптимального?
Р. Кап

Відповіді:


9

Pyth 96 94 байт

Mt*Q+++bGdHM|%+y_GHQQg1 2++Qd1g2 3g2 1g3 1++Qd2Vr3QgNtN++QdN;g1QVStQVStQI<NHgnNHnNtH)++nN0dnNH

Спробуйте тут

Як це працює?

Для цього пояснення буде використовувати N = 5.

Частина 1: Створіть нижній шар на кожному стеку

Причина, чому для цього потрібен окремий фрагмент коду, полягає в тому, що потрібно використовувати кожен стек: перші 4 потребують 5 під ними, а останній стек повинен містити 5s. Це означає, що ми не можемо просто перенести всі кудись кудись, поставити туди 5 і повернути 4 назад.

Візуалізація: (дужки означають, що буде переміщено)

     _
11111 |
22222 |_ Can't move 4s here, not monotonically increasing
33333_|
(44444)------------??? Where to put the 4s?
55555 <- Must supply the 5 that will be moved

Замість цього, щоб зробити цей перший обмін, ми спочатку перемістимо всі 1s на другий стек, перемістимо 5 на перший стек (який тепер порожній), перемістимо 1s на третій стек, перемістимо 2s на перший стек, перемістіть 1s назад до першого стека і, нарешті, перемістіть 5 на другий стек.

(11111)-----.
2222211111<-'
===============================
5<---------.
2222211111 : (from stack 5)
===============================
5
22222(11111)-.
3333311111<--'
===============================
522222<-.
(22222)-'
3333311111
===============================
52222211111<-.
             |
33333(11111)-'
===============================
52222211111
5<-----.
33333  |
44444  |
555(5)-'

Тепер, коли у нас є вільний простір для переміщення стеків у (стек 2, який містить лише 5, розміщений у потрібному місці), ми можемо перемістити всі 3 у стек 2 і помістити 5 у стек 3. Потім можна повторити те ж саме для стека 4, і тепер ми отримуємо всі 5-ти в потрібному місці! І лише ще одна річ: ми перемістимо всі 1 на стек 5, щоб отримати гарну настройку для наступного обміну стеками.

522222(11111)-.
533333        |
544444        |
5             |
511111<-------'

Частина 2: Робіть все інше :)

Зараз це набагато простіше, адже зараз у нас завжди буде вільний стек для переміщення інших номерів, на які нам потрібно перемикатись. Отже, спочатку розберемося, де знаходиться 4. Трохи експертизи покажуть, що це завжди буде 1 вгору від місця, де він розпочався, або 2 вище останнього стека. Тепер ми просто продовжуємо знижувати стеки, поміщаючи 4 у стек, якщо він безкоштовний, або переміщуючи інші числа вгору на 1 стек, якщо це не так. Тепер у нас всі 4-х на місці.

522222<------.
533333<----. |
544444-.-.-'-'
5<-----' |
511111<--'
===============================
5433333
54
54
5411111
5422222

Тепер ми розуміємо, що 3s - це 2 стеки вище, де 4s, де. Це означає, що ми можемо зробити те саме, що ми зробили з 4-х! І як виявляється, ми можемо продовжувати це робити до тих пір, поки обернемо індекс стека на інший бік.

5433333-'wrap around 543
54                   543
54                   54311111
5411111 .----------->54322222
5422222 |2 stacks up 543

І так, ми можемо продовжувати це робити, поки не обміняємось усіма стеками.

Пояснення коду:

Перш за все: (важливі) заздалегідь визначені змінні.

Q: Evaluated input.
b: The newline character, '\n'
d: A space, ' '

Є 2 лямбда-визначення.

M           | g(G)(H), used for moving Q numbers at a time.
            | We will call these Q numbers a "(number) block"
 t          | Tail, used to remove beginning newline
  *Q        | Repeat the following Q times
    +++bGdH | '\n' + G + ' ' + H. Just a whole bunch of concatenating.
            |
M           | n(G)(H), used for figuring out which stacks to move from
 |       Q  | If the following code is 0 (false), then use Q instead
  %     Q   | Mod Q
   +   H    | Add H
    y       | Multiply by 2
     _G     | Negate (remember in the explanation part 2? Always 2 stacks above?)

Обмін стеками: частина 1

g1 2                       | Move the 1 block to stack 2
    ++Qd1                  | Move a Q to stack 1
         g2 3              | Move the 1 block to stack 3
             g2 1          | Move the 2 block to stack 1
                 g3 1      | Move the 1 block back to stack 1
                     ++Qd2 | Move a Q to stack 2
 v---Code-continuation---' |I don't have enough room!!!
Vr3Q                       | For N in range(3, Q)
    gNtN                   | Move the number block in stack N up 1
        ++QdN              | Move a Q to stack N
             ;g1Q          | End for loop; move the 1 block to the last stack

Обмін стеком: частина 2

VStQ                           | For N in [1, 2, ..., Q - 1]
    VStQ                       | For H in [1, 2, ..., Q - 1]
        I<NH                   | If N < H
            g                  | Number block move
             nNH               |  (find number block)
                nNtH           |  (find the previous stack)
                    )          | End "For H"
                     ++nN0dnNH | Find start, move number to next location down

Я вже знаю, що я не отримую очок брауні, бо я можу побачити багато більш ефективних і складніших методів :(

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.