Перегортаючи млинці


27

У сортуванні млинців єдиною дозволеною операцією є повернення елементів деякого префіксу послідовності. Або придумайте стопку млинців: ми вставляємо десь у стопку шпатель і перевертаємо всі млинці над шпателем.

Наприклад, послідовність 6 5 4 1 2 3можна сортувати, спочатку прогортаючи перші 6елементи (всю послідовність), даючи проміжний результат 3 2 1 4 5 6, а потім гортаючи перші 3елементи, доходячи до 1 2 3 4 5 6.

Оскільки існує лише одна операція, весь процес сортування може бути описаний послідовністю цілих чисел, де кожне ціле число - це кількість елементів / млинців, які повинні включати pr flip. У наведеному вище прикладі послідовність сортування була б 6 3.

Інший приклад: 4 2 3 1можна сортувати за 4 2 3 2. Ось проміжні результати:

         4 2 3 1
flip 4:  1 3 2 4
flip 2:  3 1 2 4
flip 3:  2 1 3 4
flip 2:  1 2 3 4

Завдання:

Напишіть програму, яка містить список цілих чисел та друкує дійсну послідовність сортування млинців.

Список для сортування може бути списком, відокремленим пробілом від stdin, або аргументами командного рядка. Роздрукувати список, проте це зручно, доки він дещо читабельний.

Це кодегольф!

Редагувати:

Як я вже говорив у коментарях, вам не потрібно оптимізувати вихід (пошук найкоротшої послідовності є важким для NP ). Однак я просто зрозумів, що дешевим рішенням буде викинути випадкові числа, поки ви не отримаєте бажаного результату ([новий?] Тип богосорту). Жоден із відповідей поки що цього не зробив, тому я заявляю, що ваш алгоритм не повинен покладатися на будь-яку (псевдо-) випадковість .

Поки ви все б’єте себе, ось варіант богопанкексарт в Ruby 2.0 (60 символів), щоб втерти його в:

a=$*.map &:to_i
a=a[0,p(v=rand(a.size)+1)].reverse+a[v..-1]while a!=a.sort

1
Будь-яка дійсна послідовність, або вона повинна бути мінімальною довжиною?
Пітер Тейлор

Tiny typo: другий приклад показує 4 3 2 1замість4 2 3 1
beary605

4
(Мій Інтернет знизився, коли я спробував це відредагувати, тому надсилаю його ще раз) @PeterTaylor Я спокусився включити в це якусь оптимізацію, але вирішив не робити. Пошук довжини мінімальної послідовності насправді є NP-важким , тоді як найпростіший прямолінійний алгоритм може знайти рішення, яке не може перевищувати 2n. Я не знаю, як би я оцінив це як виклик коду / оптимальний вихідний результат, і мені просто подобається звичайний кодовий гольф більше :)
daniero

Цікаво, чи хтось опублікує свою заявку з цього виклику .
grc

Чи повинна послідовність мати суміжні значення? Чи дійсно 2 7 5 вхідним?

Відповіді:


6

GolfScript, 34/21 символів

(Дякуємо @PeterTaylor за рубання 4 символів)

~].{,,{1$=}$\}2*${.2$?.p)p.@\-+}/,

Інтернет-тест

Коротша версія з 21 символом працює лише для списків з унікальними елементами

~].${.2$?.p)p.@\-+}/,

Інтернет-тест

Обидві версії виробляють неоптимальні рішення.


Пояснення до коротшого рішення:

~]         # read input from stdin
.$         # produce a sorted copy from lowest to highest
{          # iterate over the sorted list
  .2$?     # grab the index of the element
  .p       # print the index
  )p       # increment and print the index
  .@\-+    # move the element to the front
}/
,          # leave the length of the list on the stack
           # this flips the reverse sorted list to become sorted

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

Для переміщення n-го елемента спереду:

1 2 3 4 5 6 7   # let's move the 3rd (0-based) element to the front
# flip the first 3 elements
3 2 1 4 5 6 7
# flip the first 3+1 elements
4 1 2 3 5 6 7

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


Насправді алгоритм - це варіація 90-ти канального рішення Python (я, звичайно, мій):

d=map(int,raw_input().split());i=0
while d:n=d.index(max(d));d.pop(n);print n+i,n-~i,;i+=1

2
Я бачу, що ви не натрапили на одну з корисних примх GolfScript: ви можете використовувати будь-який маркер як змінну. Ви не використовуєте в &будь-якому місці, так що ви повинні бути в змозі замінити в sтой час як &і видалити пробіл.
Пітер Тейлор

@PeterTaylor так, мені було цікаво, чому ти можеш використовувати ^як змінну у складі виклику;) Дякую за підказку!
Волатильність

Для введення 3 2 1я отримую, 131211що невірно.
Говард

@Howard змусив його працювати зараз
волатильність

@Volatility Остання зміна була занадто великою ;-) Напр. Списки, як, наприклад, 2 1 1більше не можна сортувати.
Говард

11

Пітон, 91 90 символів

L=map(int,raw_input().split())
while L:i=L.index(max(L));print-~i,len(L),;L=L[:i:-1]+L[:i]

Переверніть найбільший млинець до верху, а потім переверніть всю стопку. Зніміть найбільший млинець знизу і повторіть.

i- це показник найбільшого млинця. L=L[:i:-1]+L[:i]гортає i+1млинці, гортає len(L)млинці, потім скидає останній млинець.


1
Я думав, що вам дозволяють робити лише сальто. (Тобто я не думав, що ти можеш скинути млинці зі стопки). Я неправильно зрозумів правила? Хм. знову читає сторінку вікі Незалежно, приємна робота :) Менше ніж 100 символів для мене досить дивовижно!
WendiKidd

@WendiKidd Насправді, що він має на увазі, що після перекидання найбільшого на дно, він просто ігнорує це і стосується себе млинців зверху.
AJMansfield

@AJMansfield Ах, бачу! Дякую, це має сенс. Я не можу прочитати код (я занадто новачок у Python), тому я неправильно зрозумів пояснення :) Дякую!
WendiKidd

2
Досить велика еволюція того, що я писав раніше. Я не думав видаляти елементи, тому що на початку мені довелося перевірити правильність виводу (тобто сортується список згодом?). До речі: я вважаю, що вилучення кома з цього приводу printробить результат нечитабельним (1 байт збережено :)
Bakuriu

@WendiKidd насправді при подальшому огляді дійсно видаляє млинці; йому потрібно лише з'ясувати, що таке послідовність фліпсів, а не насправді сортувати масив.
AJMansfield

6

Рубін 1,9 - 109 88 79 символів

Набагато більш компактна версія, заснована на чудовому пітонному рішенні Кіта:

a=$*.map &:to_i;$*.map{p v=a.index(a.max)+1,a.size;a=a[v..-1].reverse+a[0,v-1]}

Оригінальна версія:

a=$*.map &:to_i
a.size.downto(2){|l|[n=a.index(a[0,l].max)+1,l].map{|v|v>1&&n<l&&p(v);a[0,v]=a[0,v].reverse}}

Якщо вас не хвилюють помилкові операції (повернення стеків розміром 1 або повернення одного стека двічі поспіль), ви можете зробити його трохи коротшим (96 символів):

a=$*.map &:to_i
a.size.downto(2){|l|[a.index(a[0,l].max)+1,l].map{|v|p v;a[0,v]=a[0,v].reverse}}

Приймає несортований список як аргументи командного рядка. Приклад використання:

>pc.rb 4 2 3 1
4
2
3
2

6

GolfScript, 31 29 символів

~].${1$?).p.2$.,p>-1%\@<+)}%,

Ще одне рішення GolfScript, також можна протестувати в Інтернеті .

Попередня версія:

~].$-1%{1$?).2$>-1%@2$<+.,\);}/

Як це працює: він перекидає найбільший елемент вгору, а потім на останнє місце в списку. Оскільки він зараз у правильному положенні, ми можемо видалити його зі списку.

~]         # Convert STDIN (space separated numbers) to array
.$-1%      # Make a sorted copy (largest to smallest)
{          # Iterate over this copy
  1$?)     # Get index of item (i.e. largest item) in the remaining list,
           # due to ) the index starts with one
  .        # copy (i.e. index stays there for output)
  2$>      # take the rest of the list...
  -1%      # ... and reverse it 
  @2$<     # then take the beginning of the list
  +        # and join both. 
           # Note: these operations do both flips together, i.e.
           # flip the largest item to front and then reverse the complete stack
  .,       # Take the length of the list for output
  \);      # Remove last item from list
}/

4

Perl, 103 100 символів

Очікує введення в командному рядку.

for(@n=sort{$ARGV[$a]<=>$ARGV[$b]}0..$#ARGV;@n;say$i+1,$/,@n+1)
{$i=pop@n;$_=@n-$_-($_<=$i&&$i)for@n}

Рішення, які він друкує, безумовно, є оптимальними. (У мене була програма з набагато приємнішим результатом близько 24 символів тому ....)

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


3

Пітон 2 (254)

Простий BFS-пошук, деякі речі є вкладеними, ймовірно, можна було б стиснути більше, не змінюючи стиль пошуку. Сподіваємось, це показує, можливо, як слід трохи почати займатися гольфом (занадто багато, щоб бути у простому коментарі).

Використання:

python script.py 4 2 3 1

(2 пробіли = вкладка)

import sys
t=tuple
i=t(map(int,sys.argv[1:]))
g=t(range(1,len(i)+1))
q=[i]
p={}
l={}
while q:
 c=q.pop(0)
 for m in g:
  n=c[:m][::-1]+c[m:]
  if n==g:
   s=[m]
   while c!=i:s+=[l[c]];c=p[c]
   print s[::-1]
   sys.exit()
  elif n not in p:q+=[n];p[n]=c;l[n]=m

1
Ви можете замінити sys.exit()на 1/0(у codegolf ви ніколи не дбаєте про те, що друкується в stderr ...).
Бакуріу

Зрозуміло, я міг print s[::-1];1/0би поголити кілька чарів.
милі

BFS - це дуже цікаво, але запускати його 4 2 3 1дає 2 3 2 4, що насправді є недійсним.
daniero

1
@daniero Як це вихід недійсний? 4 2 3 1-> 2 4 3 1-> 3 4 2 1-> 4 3 2 1->1 2 3 4
Гарет

@Gareth Я поняття не маю! І я навіть перевіряв це двічі .. О добре, ніколи не пам'ятаю :) Приємне рішення, милі т.
daniero

3

Пітон2: 120

L=map(int,raw_input().split())
u=len(L)
while u:i=L.index(max(L[:u]))+1;L[:i]=L[i-1::-1];L[:u]=L[u-1::-1];print i,u;u-=1

Це неефективно: він не знайде найкращої послідовності сортування, і дана послідовність може навіть містити відсутності (тобто гортати лише перший елемент), проте результат є дійсним.

Вихід подається у вигляді:

n_1 n_2
n_3 n_4
n_5 n_6
...

Якою має бути прочитана як послідовність перебудов: n_1 n_2 n_3 n_4 n_5 n_6 .... Якщо ви хочете отримати такий результат, як:

n_1 n_2 n_3 n_4 n_5 n_6 ...

Просто додайте кому у printвиписку.


[:i][::-1]-> [i-1::-1], [:u][::-1]-> [u-1::-1], зберігає 2 символи
Волатильність

Фактично, L[:i]=L[i-1::-1];L[:u]=[u-1::-1]економиться ще 3 символи
Волатильність

@ Властивість Дякую за поради. У комплекті.
Бакуріу

3

Пітон - 282 символи

import sys
s=sys.argv[1]
l=s.split()
p=[]
for c in l:
 p.append(int(c))
m=sys.maxint
n=0
while(n==(len(p)-1)):
 i=x=g=0
 for c in p:
  if c>g and c<m:
   g=c
   x=i
  i+=1
 m=g
 x+=1
 t=p[:x]
 b=p[x:]
 t=t[::-1]
 p=t+b
 a=len(p)-n;
 t=p[:a]
 b=p[a:]
 t=t[::-1]
 p=t+b
 print p
 n+=1

Мій перший в історії кодекс гольф; Я не маю жодних ілюзій, я переможу , але мені було дуже весело. Якщо все, що однозначні імена впевнені, робить це страхітливим для читання, дозвольте сказати! Це запускається з командного рядка, зразок реалізації нижче:

Python PancakeSort.py "4 2 3 1"
[1, 3, 2, 4]
[2, 1, 3, 4]
[1, 2, 3, 4]

Немає нічого особливо особливого чи винахідливого щодо того, як я пройшов із цього питання, але FAQ часто пропонує розмістити нецікаву версію для зацікавлених читачів, тому я це зробив нижче:

import sys

pancakesStr = sys.argv[1]
pancakesSplit = pancakesStr.split()
pancakesAr = []
for pancake in pancakesSplit:
    pancakesAr.append(int(pancake))

smallestSorted = sys.maxint
numSorts = 0

while(numSorts < (len(pancakesAr) - 1)):
    i = 0
    biggestIndex = 0
    biggest = 0
    for pancake in pancakesAr:
        if ((pancake > biggest) and (pancake < smallestSorted)):
            biggest = pancake
            biggestIndex = i
        i += 1

    smallestSorted = biggest  #you've found the next biggest to sort; save it off.
    biggestIndex += 1   #we want the biggestIndex to be in the top list, so +1.

    top = pancakesAr[:biggestIndex]
    bottom = pancakesAr[biggestIndex:]

    top = top[::-1] #reverse top to move highest unsorted number to first position (flip 1)
    pancakesAr = top + bottom   #reconstruct stack

    alreadySortedIndex = len(pancakesAr) - numSorts;

    top = pancakesAr[:alreadySortedIndex]
    bottom = pancakesAr[alreadySortedIndex:]

    top = top[::-1] #reverse new top to move highest unsorted number to the bottom position on the unsorted list (flip 2)
    pancakesAr = top + bottom   #reconstruct list

    print pancakesAr    #print after each flip

    numSorts += 1

print "Sort completed in " + str(numSorts) + " flips. Final stack: "
print pancakesAr

Основний алгоритм, який я використовував, є той, який згадується у статті wiki, пов'язаній у запитанні :

Найпростіший алгоритм сортування млинців вимагає максимум 2n-3 фліп. У цьому алгоритмі, варіації вибору сорту, ми приводимо найбільший ще не відсортований млинець на вершину одним обертанням, а потім переносимо його до остаточного положення ще одним, потім повторюємо це для інших млинців.


1
Деякі поради щодо гольфу: чотири місця для відступу є марними. Краще: використовувати один пробіл; ще краще: комбінуйте вкладки та пробіли, щоб скоротити ще більше.
Джон Дворак

1
t=p[:x] t=t[::-1](16 + відступ) можна зменшити до t=p[:x][::-1](13) або навіть t=p[x-1::-1](12). Вбудуйте все, що можете:p=p[x-1::-1]+p[x:]
Джон Дворак

Використовуйте від'ємні показники, щоб рахувати з зворотного боку. len(a)-nстає -n; p=p[-n-1::-1]+p[-n:]. Далі гольф, використовуючи правильні операції:p=p[~n::-1]+p[-n:]
Джон Дворак

1
Гм ... ви повинні надрукувати всю послідовність гортання, а не лише кінцевий результат.
Джон Дворак

Що сказав Ян Дворак. Ласкаво просимо до codegolf. Ви можете легко скоротити кількість символів до половини за допомогою простих заходів; деякі з них були згадані. Крім того, проміжні змінні не є корисними. Розуміння списку приємно. Але якщо ви використовуєте sys.argv, ви можете також дозволити, що кожне число вхідного аргументу є аргументом, то map(int,sys.argv[1:])робить те, що зараз робить ваші 6 перших рядків. i=x=g=0працює, але ви все одно повинні скоротити кількість змінних. Я дам вам одне, однак: Це той пітон, який я найменше розумію: D
daniero

3

C # - 264 259 252 237 символів

Використовується найпростіший алгоритм і виробляє правильний вихід без зайвих фліп. Я міг би відтерти 7 знаків, якщо я дозволив би включити у висновок 1 (не перевертає), але це некрасиво.

Я вдався до використання gotoдля максимального гольфу. Також збережено деякі символи, дозволяючи виконувати його без перекидання (але не друкувати їх).

Останнє вдосконалення: зберігання вхідного масиву як рядків замість перетворення в ints.

using System.Linq;class P{static void Main(string[]a){var n=a.ToList();for(int p
=n.Count;p>0;p--){int i=n.IndexOf(p+"")+1;if(i<p){f:if(i>1)System.Console.Write
(i);n=n.Take(i).Reverse().Concat(n.Skip(i)).ToList();if(i!=p){i=p;goto f;}}}}}

Безголівки:

using System.Linq;
class Program
{
    static void Main(string[] args)
    {
        var numbers = args.ToList();

        for (int pancake = numbers.Count; pancake > 0; pancake--)
        {
            int index = numbers.IndexOf(pancake+"") + 1;
            if (index < pancake)
            {
                flip:

                if (index > 1)
                    System.Console.Write(index);

                numbers = numbers.Take(index)
                                 .Reverse()
                                 .Concat(numbers.Skip(index))
                                 .ToList();

                if (index != pancake)
                {
                    index = pancake;
                    goto flip;
                }
            }
        }
    }
}

Ось моє початкове рішення, безголів (264 символи в гольфі):

using System.Linq;
using System;

class Program
{
    static void Main(string[] args)
    {
        var numbers = args.Select(int.Parse).ToList();

        Action<int> Flip = howMany =>
        {
            Console.Write(howMany);
            numbers = numbers.Take(howMany)
                             .Reverse()
                             .Concat(numbers.Skip(howMany))
                             .ToList();
        };

        for (int pancake = numbers.Count; pancake > 0; pancake--)
        {
            int index = numbers.IndexOf(pancake) + 1;
            if (index < pancake)
            {
                if (index > 1)
                    Flip(index);
                Flip(pancake);
            }
        }
    }
}

Не обробляє непослідовні послідовності - даючи неправильні результати з цими введеннями.

@hatchet: Я не впевнений, що ти маєш на увазі. Чи можете ви надати мені приклад?
Ігбі Ларгеман

Враховуючи вхід 1 22, результат говорить про те, щоб зробити один своп, що призведе до 22 1. Я думаю, що ваш код очікує, що послідовність включає суміжні числа (наприклад: 2 4 1 3), але не очікує введення типу ( 2 24 5 5 990).

@hatchet: Дійсно, я не робив спроб підтримати прогалини в послідовності, тому що це не мало б сенсу. Ідея сорту млинців полягає в сортуванні стопки предметів, а не групи довільних чисел. Число, пов'язане з кожним об'єктом, ідентифікує його правильне положення в стеку. Тому цифри завжди починатимуться з 1 і будуть суміжними.
Ігбі Ларгеман

Я не був впевнений, тому що в запитанні було сказано "послідовність", а з математики {1, 22} є дійсною послідовністю, але обидва приклади були суміжними числами. Тож я попросив роз’яснень у ОП (див. Коментарі до питання). Я думаю, що більшість відповідей тут буде справляти прогалини.


2

Perl 5,10 (або вище), 66 байт

Включає +3в довести мову до рівня Perl 5,10 вважається вільним-nuse 5.10.0

#!/usr/bin/perl -n
use 5.10.0;
$'>=$&or$.=s/(\S+) \G(\S+)/$2 $1/*say"$. 2 $."while$.++,/\S+ /g

Запустити з введенням як один рядок на STDIN:

flop.pl <<< "1 8 3 -5 6"

Сортируйте список, повторно знаходячи будь-яку інверсію, перевернувши її на передню частину, потім перевернувши інверсію і перевернувши все назад у старе положення. І це рівнозначно заміні інверсії, тому мені не потрібно реверсувати (що незручно на рядках, оскільки це переверне цифри значень, що перетворюються, наприклад, 12в 21)


1

C # - 229

using System;using System.Linq;class P{static void Main(string[] a){
var n=a.ToList();Action<int>d=z=>{Console.Write(z+" ");n.Reverse(0,z);};
int c=n.Count;foreach(var s in n.OrderBy(x=>0-int.Parse(x))){
d(n.IndexOf(s)+1);d(c--);}}}

читана версія

using System;
using System.Linq;
class P {
    static void Main(string[] a) {
        var n = a.ToList();
        Action<int> d = z => { Console.Write(z + " "); n.Reverse(0, z); };
        int c = n.Count;
        foreach (var s in n.OrderBy(x => 0 - int.Parse(x))) {
            d(n.IndexOf(s) + 1); d(c--);
        }
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.