Листать блины


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-сложная задача ). Однако я только что понял, что дешевым решением будет выбрасывать случайные числа, пока вы не получите желаемый результат (тип [new?] Bogosort). Ни один из ответов до сих пор не сделал этого, поэтому я сейчас заявляю, что ваш алгоритм не должен полагаться на какую-либо (псевдо-) случайность .

Пока вы все бьетесь, вот вариант bogopancakesort в 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
Любая действительная последовательность или она должна быть минимальной длины?
Питер Тейлор

Крошечная опечатка: второй пример показывает 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

Он повторяет эту операцию для каждого элемента по порядку и заканчивается обратным отсортированным списком. Затем он переворачивает весь список, чтобы оставить его полностью отсортированным.


Фактически алгоритм представляет собой вариант решения Python из 90 символов (мое собственное, конечно):

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: вы можете использовать любой токен в качестве переменной. Вы &нигде не используете , так что вы должны иметь возможность заменить swhile &и удалить пробелы.
Питер Тейлор

@PeterTaylor да, мне было интересно, почему вы можете использовать ^в качестве переменной в задаче Фибоначчи;) Спасибо за совет!
Волатильность

Для ввода 3 2 1я получаю 131211что не правильно.
Говард

@ Ховард заставил это работать сейчас
Волатильность

@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

Ruby 1,9 - 109 88 79 символов

Гораздо более компактная версия, основанная на отличном Python-решении Кейта:

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

Python 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, что на самом деле неверно.
Даньеро

1
@daniero Как этот вывод неверен? 4 2 3 1-> 2 4 3 1-> 3 4 2 1-> 4 3 2 1->1 2 3 4
Гарет

@ Гарет, я понятия не имею! И я даже проверил это дважды .. Ну, ладно, тогда неважно :) Отличное решение, миль т.
Даньеро

3

Python2: 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

Он не эффективен: он не найдет наилучшую последовательность сортировки, и данная последовательность может даже содержать no-ops (т. Е. Переключать только первый элемент), тем не менее, вывод верен.

Выход дается в виде:

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 символа
Волатильность

@ Volatility Спасибо за советы. В комплекте.
Бакуриу

3

Python - 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

Основной алгоритм, который я использовал, - это тот, который упоминается в статье вики, связанной с вопросом :

Самый простой алгоритм сортировки блинов требует не более 2–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работает, но вы все равно должны сократить количество переменных. Я скажу вам одну вещь: это единственная запись на
питоне,

3

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

Использует самый простой алгоритм и производит правильный вывод без избыточных переворотов. Можно было бы сбрить 7 символов, если бы я позволил включить 1 (не флипс) в вывод, но это ужасно.

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

Последнее улучшение: сохранение входного массива в виде строк вместо преобразования в целые.

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;}}}}}

Ungolfed:

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

Haskell , 72 71 байт

h s|(a,x:b)<-span(<maximum s)s=map length[x:a,s]++h(reverse b++a)
h e=e

Попробуйте онлайн! Находит максимум, переворачивает его назад и рекурсивно сортирует оставшийся список.

Редактировать: -1 байт благодаря BMO


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.