翻转煎饼


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-hard)。但是,我刚刚意识到,一种便宜的解决方案是丢弃随机数,直到获得所需的结果为止(一种新的bogosort类型)。到目前为止,没有任何答案可以做到这一点,因此,我现在声明您的算法不应依赖任何(伪随机)随机性

当您自己动手时,以下是Ruby 2.0中的bogopancakesort变体(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-hard的,而最简单,直接的算法可以找到最大2n长的解决方案。我真的不知道如何将其判断为代码挑战/最佳输出,并且我更喜欢普通的codegolf :)
daniero

我想知道是否有人会在这次挑战中发表他们的观点。
grc

序列必须是连续值吗?2 7 5是有效输入吗?

Answers:


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

Python,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 2013年

@WendiKidd实际上,他的意思是,在将最大的一个翻到底部之后,他只是忽略了它,而在上面放着煎饼来关心自己。
AJMansfield

@AJMansfield啊,我明白了!谢谢,这很有意义。我看不懂代码(我对Python还是太陌生),所以我误解了解释:)谢谢!
WendiKidd 2013年

2
几乎是我以前写的东西的演变。我没有考虑删除元素,因为在开始时我必须检查输出的正确性(即列表之后是​​否排序?)。顺便说一句:我相信从print不会删除逗号会使输出变得不可读(保存了1个字节:)
Bakuriu

@WendiKidd实际上,在进一步检查中,确实确实除去了薄煎饼;它只需要弄清楚翻转的顺序是什么,而不必对数组进行排序。
AJMansfield

6

红宝石1.9 - 109 88 79个字符

基于Keith出色的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,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个字符。...)

逻辑有点有趣。首先,对每个项目的索引进行分类(按排序顺序)。然后,它从右到左遍历此目录。因此,应用翻转需要将索引调整到截止值以下,而不是实际移动值。经过一些整理之后,我还设法通过每次迭代同时进行两次翻转来节省了一些字符。


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中打印出的内容...)。
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

的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

它效率不高:它将找不到最佳的排序顺序,并且给定的顺序甚至可以包含无操作(即仅翻转第一个元素),但是输出仍然有效。

输出形式为:

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

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

我使用的基本算法是问题中链接Wiki文章中提到的算法:

最简单的煎饼分类算法最多需要2n-3次翻转。在此算法中,这是选择排序的一种变体,我们将尚未排序的最大煎饼移到顶部,然后再翻转一次使其降至最终位置,然后对其余的煎饼重复此操作。


1
打高尔夫球的一些技巧:四个缩进空间是浪费的。更好:使用一个空间;更好:将制表符和空格组合在一起以减少更多内容。
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可以,但是无论如何您应该减少变量的数量。不过,我会给你一件事:这是我最不了解的一个python条目:D
daniero 2013年

3

C# - 264个259 252 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;
                }
            }
        }
    }
}

这是我最初的解决方案,没有高尔夫球(打了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

给定1 22的输入,结果表示进行一次交换,结果为221。我认为您的代码希望序列包含连续的数字(例如2 4 1 3),但不要期望输入( 2 24 5 5 990)。

@hatchet:确实,我没有尝试支持序列中的差距,因为那没有意义。煎饼分类的想法是对一堆对象进行分类,而不是对一组任意数字进行分类。与每个对象关联的数字标识其在堆栈中的正确位置。因此,数字将始终以1开头并且是连续的。
Igby Largeman

我不确定,因为问题是“序列”,在数学上,{1,22}是有效序列,但是两个示例都是连续的数字。因此,我要求OP做出澄清(请参阅问题注释)。我认为这里的大多数答案都会弥补差距。

2

Haskell72 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用于-nuse 5.10.0带来的语言水平的Perl 5.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"

对列表进行排序,方法是反复查找任何反转,将其翻转到最前面,然后反转,然后将所有内容翻转回原来的位置。这是等同于交换反转,所以我不需要反向(这是对串尴尬,因为这将扭转值的数字转换如1221


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--);
        }
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.