パンケーキの反転


27

パンケーキソートのみ許可される操作をシーケンスの一部の接頭辞の要素を逆にすることです。または、パンケーキのスタックを考えます。スタックのどこかにヘラを挿入し、スパチュラの上にすべてのパンケーキをひっくり返します。

たとえば6 5 4 1 2 3、最初の6要素(シーケンス全体)を最初に反転し、中間結果を生成して3 2 1 4 5 6から最初の3要素を反転してに到達することにより、シーケンスをソートできます1 2 3 4 5 6

操作が1つしかないため、ソートプロセス全体を整数のシーケンスで記述できます。各整数は、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からスペースで区切られたリスト、またはコマンドライン引数のいずれかです。リストを印刷しますが、多少読みやすい限りは便利です。

これはcodegolfです!

編集:

コメントで述べたように、出力を最適化する必要はありません(最短シーケンスを見つけるのは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代わりに2番目の例を示します4 2 3 1
beary605

4
(これを編集しようとしてインターネットがダウンしたので、もう一度投稿します)@PeterTaylorこれに何らかの最適化を含めたいと思いましたが、選択しませんでした。最小シーケンスの長さを見つけることは実際にはNP-hardですが、最も単純で単純なアルゴリズムでは、せいぜい2nの長さになる解を見つけることができます。これをコードチャレンジ/最適な出力と判断する方法がよくわかりません。プレーンなコードゴルフが好きです:)
ダニエル

誰かがこの挑戦からエントリーを投稿するのかしら。
-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

これは、投稿された他のほとんどのアルゴリズムとは異なるアルゴリズムを使用します。基本的に、リストの最小要素を取得し、2回フリップすることでリストを最前面に移動し、他の要素の順序を保持します。

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の便利な癖の1つに出会ったことがないようです。変数として任意のトークンを使用できます。&どこでも使用していないので、swhile を置き換え&て空白を削除できるはずです。
ピーターテイラー

@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

@WendiKidd実際、彼が意味するのは、一番大きいものを下にひっくり返した後、彼はそれを無視して、その上にパンケーキを置いて自分自身について考えているということです。
-AJMansfield

@AJMansfieldあ、なるほど!ありがとう、それは理にかなっています。私はコードを読むことができません(私はPythonにあまりにも慣れていないので)説明を誤解しました:)ありがとう!
WendiKidd

2
私が以前に書いたもののほとんど進化。最初に出力の正確さをチェックしなければならなかったので、要素を削除することを考えませんでした(つまり、リストは後でソートされますか?)。ちなみに、print
カントを

@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のスタックを反転する、または同じスタックを2回連続で反転する)を気にしない場合は、少し短くすることができます(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にあなたが標準エラー出力に印刷されます何のために気にしません...)。
バクリウ

確かに、私はprint s[::-1];1/0いくつかの文字を剃ることができました。
マイル

BFSは非常に興味深いですが、4 2 3 1gives 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
ガレス

@Garethわからない!そして、私はそれを2回チェックしさえしました。
ダニエロ

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-op(つまり、最初の要素のみを反転する)を含めることもできますが、出力は有効です。

出力は次の形式で提供されます。

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

初めてのコードゴルフ。私は勝つだろうと幻想を抱いているわけではありませんが、とても楽しかったです。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つで最終位置に降ろしてから、残りのパンケーキについてこれを繰り返します。


1
ゴルフのためのいくつかのヒント:インデントのための4つのスペースは無駄です。良い:スペースを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動作しますが、とにかく変数の量を減らす必要があります。私はあなたに一つのことをあげます:これは私が最も理解していないPythonエントリの1つです:D
daniero

3

C#-264 259 252 237文字

最も単純なアルゴリズムを使用し、冗長なフリップなしで正しい出力を生成します。出力に1(フリップ以外)を含めることを許可した場合、7文字を削ることができますが、それは見苦しいです。

私はgoto最大のゴルフに使うことに頼りました。また、非フリップを実行できるようにすることでいくつかの文字を保存しました(ただし、印刷はしません)。

最新の改善:入力配列をintに変換する代わりに文字列として保持します。

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 chars golfed)があります:

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の場合、結果は1つのスワップを実行するように指示します。これにより、22 1になります。 2 24 5 5 990)。

@hatchet:確かに、シーケンスのギャップをサポートしようとはしませんでした。それは意味をなさないからです。パンケーキソートの考え方は、任意の数のグループではなく、オブジェクトのスタックをソートすることです。各オブジェクトに関連付けられた番号は、スタック内の適切な位置を識別します。したがって、番号は常に1で始まり、連続します。
イグビーラージマン

質問では「シーケンス」と言っていたため、定かではありませんでした。数学では{1、22}は有効なシーケンスですが、どちらの例も連続した数字でした。だから私はOPに明確化を求めた(質問に関するコメントを参照)。ここでの答えのほとんどは、ギャップをうまく処理できると思います。


2

Perl 5.10(以降)、66バイト

含ま+3のために5.10を無料考えられているPerlのレベルに言語をもたらすために-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の1行として実行します。

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.