뒤집기 팬케이크


27

에서는 팬케이크 정렬 만 허용하는 동작 시퀀스의 일부 요소 프리픽스의 역이다. 또는 팬케이크 스택을 생각해보십시오. 스택 어딘가에 주걱을 넣고 주걱 위의 모든 팬케이크를 뒤집습니다.

예를 들어, 서열은 6 5 4 1 2 3제 반전 처음으로 분류 될 수 6중간 결과를 산출 요소 (전체 순서) 3 2 1 4 5 6다음, 제 뒤집기 3에 도착 소자 1 2 3 4 5 6.

하나의 연산 만이 있기 때문에, 전체 분류 프로세스는 일련의 정수로 설명 될 수 있으며, 여기서 각 정수는 pr 플립을 포함하는 요소 / 팬케이크의 수이다. 위의 예에서 정렬 순서 는입니다 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과 공백으로 구분 된 목록이거나 명령 줄 인수 일 수 있습니다. 읽기 쉬운 목록이라면 편리하게 목록을 인쇄하십시오.

이것은 codegolf입니다!

편집하다:

의견에서 말했듯 이 출력을 최적화 할 필요가 없습니다 (가장 짧은 시퀀스를 찾는 것은 NP-hard입니다 ). 그러나 , 나는 당신이 원하는 결과를 얻을 때까지 ([new?] 유형의 bogosort) 임의의 숫자를 버리는 것이 싼 해결책이라는 것을 깨달았습니다. 지금까지 아무도 대답 을하지 않았 으므로 이제 알고리즘이 (의사) 임의성에 의존해서는 안된다고 선언 합니다 .

모두 자신을 차는 동안 Ruby 2.0 (60 문자)의 bogopancakesort 변형이 있습니다.

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-hard 이며, 가장 단순하고 간단한 알고리즘은 최대 2n 길이의 솔루션을 찾을 수 있습니다. 나는 이것을 어떻게 코드 도전 / 최적의 출력물로 판단 할 것인지 잘 모른다. 그리고 나는 일반 코드 골프를 더 좋아한다. :)
daniero

누구든지이 도전 에서 자신의 항목을 게시할지 궁금합니다 .
grc

시퀀스가 연속적인 값이어야합니까? 2 7 5는 유효한 입력입니까?

답변:


6

GolfScript, 34/21 자

(4 개의 문자를 자르 신 @PeterTaylor에게 감사드립니다)

~].{,,{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

@Howard는 지금 작동하게 되었음
변동성

@Volatility 마지막 변경 사항이 너무 많았다 ;-) 예를 들어 같은리스트는 2 1 1더 이상 정렬 할 수 없습니다.
Howard

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
나는 당신이 뒤집기 만 할 수 있다고 생각했습니다. (즉, 스택에서 팬케이크를 떨어 뜨릴 수 있다고 생각하지 않았습니다). 규칙을 이해하지 못했습니까? 흠. Wiki 페이지를 다시 읽습니다. 그럼에도 불구하고, 좋은 직업 :) 100 자 미만은 나에게 정말 놀랍습니다!
WendiKidd

@WendiKidd 사실, 그가 의미하는 바는 가장 큰 것을 바닥으로 뒤집은 후, 그냥 무시하고 그 위에 팬케이크와 관련이 있다는 것입니다.
AJMansfield

@AJMansfield 아, 알겠다! 고마워요. 코드를 읽을 수 없습니다 (Python에 너무 익숙하지 않습니다). 나는 설명을 잘못 이해했습니다. :) 감사합니다!
WendiKidd

2
내가 전에 쓴 내용의 거의 진화. 처음에는 출력의 정확성을 확인해야했기 때문에 요소를 제거하려고 생각하지 않았습니다 (즉, 나중에 목록이 정렬되어 있습니까?). 그건 그렇고 : 쉼표를 제거하면 print출력을 읽을 수 없게됩니다 (1 바이트 절약 :)
Bakuriu

@WendiKidd는 실제로 추가 검사에서 팬케이크를 실제로 제거합니다. 플립 시퀀스가 ​​무엇인지 알아 내기 만하면 실제로 배열을 정렬하지는 않습니다.
AJMansfield

6

루비 1.9 - 109 88 79 자

Keith의 훌륭한 파이썬 솔루션을 기반으로 한 훨씬 더 컴팩트 한 버전 :

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

펄, 103100

명령 행에서 입력을 예상합니다.

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

인쇄하는 솔루션은 결정적으로 차선책입니다. (약 24 문자 전에 훨씬 좋은 출력을 가진 프로그램을 가지고있었습니다 ....)

논리는 흥미 롭습니다. 정렬 순서대로 각 항목의 색인을 카탈로그 화하여 시작합니다. 그런 다음이 카탈로그를 오른쪽에서 왼쪽으로 반복합니다. 플립을 적용하려면 실제로 값을 이동하는 대신 컷오프 값 아래로 인덱스를 조정해야합니다. 약간의 finagling 후 나는 반복 당 두 플립을 동시에 수행하여 몇 개의 문자를 절약 할 수있었습니다.


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 당신이 표준 오류로 인쇄됩니다 무엇에 대한 관심 없다).
Bakuriu

물론, 나는 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

@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

그것은 효율적이지 않습니다 : 최상의 정렬 순서를 찾지 못하고 주어진 시퀀스는 심지어 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 팁을 주셔서 감사합니다. 포함되어 있습니다.
Bakuriu

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

내가 사용한 기본 알고리즘 은 질문에 링크 된 위키 기사 에서 언급 한 것입니다 .

가장 간단한 팬케이크 정렬 알고리즘에는 최대 2n-3 플립이 필요합니다. 선택 알고리즘의 변형 인이 알고리즘에서, 우리는 아직 분류되지 않은 가장 큰 팬케이크를 한 번의 플립으로 맨 위로 가져간 다음 한 번 더 최종 위치로 내려간 다음 나머지 팬케이크에 대해 이것을 반복합니다.


1
골프를위한 몇 가지 팁 : 들여 쓰기를위한 4 개의 공간은 낭비입니다. 더 나은 : 하나의 공간을 사용하십시오. 더 나은 : 탭과 공백을 결합하여 더 많이 줄입니다.
John Dvorak

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:]
John Dvorak

음수를 사용하여 뒤에서 세어보세요. len(a)-n된다 -n; p=p[-n-1::-1]+p[-n:]. 올바른 작업을 통해 추가 골프 :p=p[~n::-1]+p[-n:]
John Dvorak

1
음 ... 최종 결과뿐만 아니라 전체 뒤집기 시퀀스를 인쇄해야합니다.
John Dvorak

Jan Dvorak가 말한 것. 그건 그렇고 codegolf에 오신 것을 환영합니다. 간단한 측정으로 문자 수를 쉽게 반으로 줄일 수 있습니다. 그들 중 일부는 언급되었습니다. 또한 중간 변수는 좋지 않습니다. 리스트 이해력 이 좋습니다. 그러나 sys.argv를 사용하는 경우 각 입력 수를 인수로 지정할 수 있습니다. map(int,sys.argv[1:])그러면 6 개의 첫 번째 행이 수행하는 작업을 수행합니다. i=x=g=0작동하지만 어쨌든 변수의 양을 줄여야합니다. 나는 당신에게 한 가지를 줄 것입니다 : 이것은 내가 가장 적게 이해하는 하나의 파이썬 항목입니다 : D
daniero

3

C # -26459252 237 자

가장 간단한 알고리즘을 사용하고 중복 플립없이 올바른 출력을 생성합니다. 출력에 1을 포함하도록 허용하면 7 문자를 줄일 수는 있지만 추악합니다.

나는 사용에 의지했다 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;}}}}}

언 골프 드 :

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

여기 내 초기 솔루션, ungolfed (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 : 무슨 말인지 모르겠습니다. 예를 들어 주시겠습니까?
Igby Largeman 2013 년

1 22의 입력이 주어지면 결과는 하나의 스왑을 수행하여 22 1을 초래한다고 말합니다. 코드에 시퀀스에 연속적인 숫자 (예 : 2 4 1 3)가 포함될 것으로 예상하지만 ( 2 24 5 5 990).

@ hatchet : 사실, 시퀀스의 간격을 지원하려고 시도하지 않았습니다. 팬케이크 정렬의 개념은 임의의 숫자 그룹이 아닌 객체 스택을 정렬하는 것입니다. 각 객체와 관련된 숫자는 스택에서 해당 위치를 식별합니다. 따라서 숫자는 항상 1로 시작하고 연속적입니다.
Igby Largeman

질문이 "시퀀스"라고 말하고 수학에서 {1, 22}가 유효한 시퀀스이지만 두 예제 모두 연속 된 숫자이기 때문에 확실하지 않습니다. 그래서 OP에서 설명을 요청했습니다 (질문에 대한 의견 참조). 나는 대부분의 대답이 틈새를 처리 할 것이라고 생각합니다.


2

Perl 5.10 이상, 66 바이트

포함 +3에 대해 -n (가) use 5.10.05.10이 무료로 간주됩니다 펄 수준으로 언어를 가지고

#!/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--);
        }
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.