リストを整理する


8

以下の図のようなウィンドウで、アルファベット順に並べたい文字列のリストが表示されます。

ソート順ダイアログ

示されているように、5つの操作があります。

  • 上に移動[U]-選択した文字列を1つ上に移動します
  • 下に移動[D]-選択した文字列を1つ下に移動します
  • 最初に移動[F]-選択した文字列をリストの一番上に移動します
  • 最後に移動[L]-選択した文字列をリストの一番下に移動します
  • 逆[R]-リストの順序を逆にします

STDINを使用して、数値(文字列の数)を受け入れ、その後に文字列の順序付けられていないリストを続けます。各文字列は、2〜99の小文字の英字で構成されます。(上記の例は有効な入力ではありません。)

STDOUTを使用して、リストを整理する方法を印刷します。最初に、選択する項目に言及し、次にリストをアルファベット順に並べるためにその項目に対して実行する操作に言及します。

例えば: February U December F May D D June D R D...

説明:2月をクリックして上に移動1. 12月を選択して、上に移動します。5月、2回下に移動します。6月、一度下に移動し、リストを逆にして、もう一度下に移動...

有効なソリューションは明らかにたくさんあるので、できるだけ短いものを選択する必要があります。つまり、操作の数が最も少ないメソッドを選択します(上記の例では7)。

正しい出力と入力のつながりがある場合は、次の順序で解決してください。

  1. 文字列の選択が最も少ないものを選択します(上記の例では4)。

  2. 操作が最も少ないものを選択し、連続する同一の操作(1つの文字列に対して)を1つとしてカウントします(上の例では6)。

  3. 出力が最も短いものを選択します(合計文字数が最も少なく、スペースを数えます)。

  4. アルファベット順で最初に出力されるものを選択します。

これはコードゴルフです。常に正しい出力を生成する最短の送信が優先されます。

  • 2 zz abc
    • アウト zz D
  • 3 cc bb aa
    • アウト aa R
  • 4 abc def cd ccc
    • アウト abc L R
  • 6 rr mm nn oo qq pp
    • アウト pp U rr L

追加の例(Scott Leadley提供、エラーはypnypnのものではなく、私のものです)

いくつかの難しいケース:

  • IN => OUT
  • 6 xx aa dd bb ee cc => dd L ee L xx L
  • 7 aa bb ee cc dd ff gg => ee D D
  • 8 dd ww aa bb cc xx yy zz => ww D D D dd D D D
    • しないであろう移動のminimial数cc F bb F aa F

aa bb cc dd長さが> 1のソートパスを持つ4つのアイテムの順列

  • IN => OUT
  • 4 aa cc dd bb => bb F D
  • 4 aa dd cc bb => aa L R
  • 4 bb aa dd cc => aa F cc U
  • 4 bb dd aa cc => aa F cc U
  • 4 bb dd cc aa => bb D D R
  • 4 cc aa bb dd => cc D D
  • 4 cc aa dd bb => bb F aa F
  • 4 cc bb aa dd => dd F R
  • 4 cc bb dd aa => dd F R
  • 4 cc dd aa bb => bb F aa F
  • 4 cc dd bb aa => cc D R
  • 4 dd aa cc bb => aa L R
  • 4 dd bb aa cc => cc F D R
  • 4 dd bb cc aa => bb D R
  • 4 dd cc aa bb => aa D R

テーマによるバリエーションaaaaa bbbb ccc dd、文字列の長さが異なる4つのアイテム:

  • IN => OUT
  • 4 ccc dd aaaaa bbbb => ccc L dd L
  • 4 bbbb aaaaa dd ccc => bbbb D dd D
  • 4 bbbb dd aaaaa ccc => dd L bbbb D
  • 4 ccc aaaaa dd bbbb => ccc L dd L
  • 4 ccc dd bbbb aaaaa => dd F R
  • 4 dd bbbb ccc aaaaa => ccc R D
  • 4 dd ccc aaaaa bbbb => bbbb R D

あなたの例は、少なくとも2つの点で仕様に矛盾しているようです。2〜99の小文字の英字ではない文字列があり、A存在しないコマンドがあります。
Peter Taylor

1
正しい出力を備えたいくつかのサンプル入力を提供できますか?
Claudiu 2014

4
おもしろいことに、Vimはこれらすべてのアクションを実行します:U = ddkP、D = ddp、F = ddggP、L = ddGp、R = :g/^/m0。:P
ドアノブ

2
もっと洗練された例を望んでいました。私は証明可能すぐにばかげ取得あらゆる可能性を超える幅優先探索、なしで最短解決策を見つける方法を考え出すのトラブルを抱えている
クラウディウ

2
最小限の操作を保証したい場合は、計算上困難な状況にあることを指摘しておきます。*並べ替えに必要な比較の最小数を知っていても、現時点では最大15項目しか知られていません。「サイキックソートアルゴリズム」を参照してください。
HostileForkはSEを信頼してはならないと

回答:


2

Python 2-593 521

非常にブルートフォースで効率が高いため、実際に終了します。私がテストしている6項目のリストは、私のラップトップで約5秒かかっています。

$ time echo 5 xx aa dd bb ee cc | python order.py
dd L ee L xx L

real    0m4.444s
user    0m4.388s
sys 0m0.051s

入力の数値は無視していることに注意してください。役に立たない。

import sys
def d(l,s,o,f):
 p=len(o)
 tl=tuple(l)
 if tl in s and p>=len(s[tl]) or f and p>=len(f):
  return
 if l==sorted(l):
  return o if not f or p<len(f) else None
 s[tl]=o
 x=d(l[::-1],s,o+[l[-1]+' R'],f)or f
 for n,i in enumerate(l):
  for j,k in ([(l[:n]+[l[n+1],l[n]]+l[n+2:],'D'),(l[:n]+l[n+1:]+[l[n]],'L')]if(n!=len(l)-1)else[])+([(l[:n-1]+[l[n-1],l[n]]+l[n+1:],'U'),([l[n]]+l[:n]+l[n+1:],'F')]if(n!=0)else[]):
   x=d(j,s,(o+[i+' '+k]),x)or x
 return x
print ' '.join(d(sys.stdin.read().split()[1:],{},[],[]))

うーん、同じ値に対する複数の操作を正しく処理していないことに気づきました。修正しようと思います。


0

Ruby 2.0

演算子セット[U、D、F、L]を使用すると、リストをソートするために選択する文字列の最小数は、リスト内のアイテム数から最も長い共通のサブシーケンスを引いたものになります。R演算子を追加するには、文字列を逆にして同じルールを適用します。残念ながら、文字列の選択を最小限にすることは、操作の数を最小限にすることと同じではありません。たとえば、の入力の8 dd ww aa bb cc xx yy zz場合、正しい答えはww D D D dd D D Dですが、操作の数が最も少ない(質問の他の基準を満たす)のはになりますcc F bb F aa F。つまり、可能なソートパスのセットのはるかに大きな部分を調査する必要があります。


このソリューションでは、深さ優先の検索戦略とアルファベータ剪定を使用します。検索深度を最小限に抑えるには、アルファ値を急速に下げることが重要です。そうしないと、検索ツリーが指数関数的に爆発します。たとえば、OPの紹介例の最小スコアでソートパスを決定するには、カレンダーの順序で月を字句順にソートするのに、このプログラムの現在のスコアリング方法ではおそらく数十年かかります。プログラムは、文字列選択の最小数である8を非常に迅速に見つけます。残念ながら、それでもまだ巨大なツリーが残っています。

次の理由により、スコアリング関数としてgnome sortを使用しています。

  1. 理解して修正するのは簡単です
  2. スコアリングは通常、すぐに最適なアルファに収束します
  3. この実装は、LCS関数の実装よりも高速です
  4. LCS機能よりもゴルフが上手になります

番号4で十分です。それ以外はすべてボーナスです。

深さ優先検索では、操作が探索される順序が検索時間に大きな影響を与えます。空でないN個のアイテムのセットは、N-1以下のF(irst)またはL(ast)操作でソートできるため、これらの操作が最初に試行されます。

# gnome sort
def gnomeSort(a)
    selects = 0
    previous = nil
    i = 1
    while i < a.size
        if a[i-1] <= a[i]
            # the array a[0..i] is sorted
            i += 1      # take another bite
        else
            if a[i] != previous
                previous = a[i]
                selects += 1
            end
            a[i], a[i-1] = a[i-1], a[i]
            if (i > 1)
                i -= 1
            end
        end
    end
    return selects
end
def score(a)
    return gnomeSort(a.dup)
end

# squeeze out unnecessary operands
def consolidate(a)
    # separate operands and operators
    x = []                      # operands
    f = []                      # operators
    a.each_slice(2) { |a,b|
        x << a
        f << b
    }
    n = x.size                  # number of (operand operator) pairs
    if n>=2
        # replace all R operands with the lexically lower operand
        #   from the right or left
        f.each_with_index{|v,i|
            if v=='R'
                leftOperand = x[i-1]
                rightOperand = x[i+1]
                # handle left & right edge cases
                leftOperand = rightOperand.succ  if i==0
                rightOperand = leftOperand.succ  if i>=n-1
                x[i] = [leftOperand, rightOperand].min
            end
        }

        # replace repeated operands with <nil>
        x = x.chunk{|e|e}.map{|v|v[1].fill(nil,1)}.flatten
    end
    return [x, f]
end

@solutions = []
@operation = []
@operation[3] = ->(a, i) {
        # swap a[i] and a[i-1]
        return nil  if i<1 || i>=a.size
        v = a[i]
        a[i-1], a[i] = a[i], a[i-1]
        return [ v, 'U' ]
    }
@operation[0] = ->(a, i) {
        # move a[i] after a.last
        return nil  if i+1>=a.size
        a.push(v=a.delete_at(i))
        return [ v, 'L' ]
    }
@operation[4] = ->(a, i) {
        # reverse the whole array
        v = a[i]
        a.reverse!
        return [ v, 'R' ]
    }
@operation[1] = ->(a, i) {
        # move a[i] before a.first
        return nil  if i<=0
        a.unshift(v=a.delete_at(i))
        return [ v, 'F' ]
    }
@operation[2] = ->(a, i) {
        # swap a[i] and a[i+1]
        return nil  if i<0 || i+1>=a.size
        v = a[i]
        a[i], a[i+1] = a[i+1], a[i]
        return [ v, 'D' ]
    }

def alphaSort(depth, a, selected, selects, sortPath)
  depth += 1
  return  if selects > @alpha
  return  if selects>@alpha || selects+depth>a.size+1
  if a.each_cons(2).all?{ |x, y| x <= y }
    # found a sort path
    @alpha = selects
    @solutions << sortPath.flatten.compact
  else
    selectsFromHere = score(a)
    if @alpha > selects+selectsFromHere
      @alpha = selects+selectsFromHere
    else
    end
    @operation.each do |op|
      a.each_index do |i|
        b = a.dup
        branch = sortPath.dup << op[b,i]
        alphaSort(depth, b, a[i], selects+(selected==a[i] ? 0 : 1), branch)
      end
    end
  end
end


#       input
a = ARGF.read.scan(/\w+/m)      # alternative, $*[0].scan(/\w+/m)
a.shift                         # ignore the item count

#       depth-first search of sort operations
@alpha = [a.size-1, score(a), score(a.reverse)+1].min + 1
alphaSort(0, a, nil, 0, [])

#       winnow the set of solutions
# determine the minimum number of string selects to solve
# short-circuit if selects to solve is 0 (already sorted)
@solutions.map!{|v|consolidate v}
minSelects = @solutions.map{|v|v[0].compact.size}.min
if !minSelects
    puts
    exit
end
# keep only solutions with the minimum number of string selects
@solutions.reject!{ |v| v[0].compact.size > minSelects }

# determine the minimum number of moves in the remaining solutions
minMoves = @solutions.map{|v|v[1].size}.min
# keep only solutions with the minimum number of moves
@solutions.reject!{ |v| v[1].size > minMoves }

#       beauty contest
# turn into strings
solutions = @solutions.map{|v|v[0].zip(v[1]).flatten.compact*' '}
# keep the shortest strings
minLength = solutions.map{|v|v.size}.min
solutions.reject!{ |v| v.size > minLength }
# print the string that "that comes first alphabetically"
puts solutions.sort.first

次のperl TAPテストスイートに合格しています。

use strict;
use warnings;

use Test::More qw(no_plan);
#use Test::More tests => 61;

#       solution executable
my $solver = 'ruby2.0 sortshort.rb';
my $nonTrivial = 1;


#       "happy" path

#       examples from OP
is( `echo 2 zz abc | $solver 2>&1`, "zz D\n", 'OP example #1');
is( `echo 3 cc bb aa | $solver 2>&1`, "aa R\n", 'OP example #2');
is( `echo 4 abc def cd ccc | $solver 2>&1`, "abc L R\n", 'OP example #3');
is( `echo 6 rr mm nn oo qq pp | $solver 2>&1`, "pp U rr L\n", 'OP example #4');

# example from bizangles
is( `echo 6 xx aa dd bb ee cc | $solver 2>&1`, "dd L ee L xx L\n", 'wascally wabbit, challenges deep diver (from bizangles)');

SKIP: {
  skip('non-trivial tests', 2)  unless $nonTrivial;

  # 7 item example; bizangles' python solution (circa 2014-08-22) requires higher sys.setrecursionlimit() and takes about 5 minutes
  is( `echo 7 aa bb ee cc dd ff gg | $solver 2>&1`, "ee D D\n", 'shallow');

  # minimizing the number of selects scores better than minimizing moves
  # minimizing moves                =>  cc F bb F aa F
  # minimizing selects              =>  dd D D D D ww D D D D,  ww D D D dd D D D,  ww L U U U dd D D D,  etc.
  # minimizing selects, then moves  =>  ww D D D dd D D D
  is( `echo 8 dd ww aa bb cc xx yy zz | $solver 2>&1`, "ww D D D dd D D D\n", 'joker, minimize selects before moves');
}

#       exhaustive variations on a theme with 1 item ["aa"]
is( `echo 1 aa | $solver 2>&1`, "\n", 'permutations of 1, #1');

#       exhaustive variations on a theme with 2 items ["ab", "c"]
is( `echo 2 ab c | $solver 2>&1`, "\n", 'permutations of 2, #1');
# test OP's requirement that a string be selected before reverse operation
is( `echo 2 c ab | $solver 2>&1`, "c D\n", 'permutations of 2, #2');

#       exhaustive variations on a theme with 3 items ["five", "four", "three"]
is( `echo 3 five four three | $solver 2>&1`, "\n", 'permutations of 3, #1');
is( `echo 3 five three four | $solver 2>&1`, "four U\n", 'permutations of 3, #2');
is( `echo 3 four five three | $solver 2>&1`, "five F\n", 'permutations of 3, #3');
is( `echo 3 four three five | $solver 2>&1`, "five F\n", 'permutations of 3, #4');
is( `echo 3 three five four | $solver 2>&1`, "three L\n", 'permutations of 3, #5');
is( `echo 3 three four five | $solver 2>&1`, "five R\n", 'permutations of 3, #6');

#       selected variations on a theme with 5 items ["aa", "bb", "cc", "dd", "ee"]
is( `echo 5 aa bb cc dd ee | $solver 2>&1`, "\n", 'permutations of 5, #1, already sorted');
# two sort paths of length 1
is( `echo 5 aa bb cc ee dd | $solver 2>&1`, "dd U\n", 'permutations of 5, #2, single U or D');
is( `echo 5 aa bb ee cc dd | $solver 2>&1`, "ee L\n", 'permutations of 5, #4, single L');
is( `echo 5 bb cc aa dd ee | $solver 2>&1`, "aa F\n", 'permutations of 5, #31, single F');
is( `echo 5 ee dd cc bb aa | $solver 2>&1`, "aa R\n", 'permutations of 5, #120, reverse sorted');

#       exhaustive variations on a theme with 4 items ["aa", "bb", "cc", "dd"]
# sort paths of length 0
is( `echo 4 aa bb cc dd | $solver 2>&1`, "\n", 'permutations of 4, #1');
# sort paths of length 1
is( `echo 4 aa bb dd cc | $solver 2>&1`, "cc U\n", 'permutations of 4, #2');
is( `echo 4 aa cc bb dd | $solver 2>&1`, "bb U\n", 'permutations of 4, #3');
is( `echo 4 aa dd bb cc | $solver 2>&1`, "dd L\n", 'permutations of 4, #5');
is( `echo 4 bb aa cc dd | $solver 2>&1`, "aa F\n", 'permutations of 4, #7');
is( `echo 4 bb cc aa dd | $solver 2>&1`, "aa F\n", 'permutations of 4, #9');
is( `echo 4 bb cc dd aa | $solver 2>&1`, "aa F\n", 'permutations of 4, #10');
is( `echo 4 dd aa bb cc | $solver 2>&1`, "dd L\n", 'permutations of 4, #19');
is( `echo 4 dd cc bb aa | $solver 2>&1`, "aa R\n", 'permutations of 4, #24');

# sort paths of length 2
is( `echo 4 aa cc dd bb | $solver 2>&1`, "bb F D\n", 'permutations of 4, #4');
is( `echo 4 aa dd cc bb | $solver 2>&1`, "aa L R\n", 'permutations of 4, #6');
is( `echo 4 bb aa dd cc | $solver 2>&1`, "aa F cc U\n", 'permutations of 4, #8');
is( `echo 4 bb dd aa cc | $solver 2>&1`, "aa F cc U\n", 'permutations of 4, #11');
is( `echo 4 bb dd cc aa | $solver 2>&1`, "bb D D R\n", 'permutations of 4, #12');
is( `echo 4 cc aa bb dd | $solver 2>&1`, "cc D D\n", 'permutations of 4, #13');
is( `echo 4 cc aa dd bb | $solver 2>&1`, "bb F aa F\n", 'permutations of 4, #14');
is( `echo 4 cc bb aa dd | $solver 2>&1`, "dd F R\n", 'permutations of 4, #15');
is( `echo 4 cc bb dd aa | $solver 2>&1`, "dd F R\n", 'permutations of 4, #16');
is( `echo 4 cc dd aa bb | $solver 2>&1`, "bb F aa F\n", 'permutations of 4, #17');
is( `echo 4 cc dd bb aa | $solver 2>&1`, "cc D R\n", 'permutations of 4, #18');
is( `echo 4 dd aa cc bb | $solver 2>&1`, "aa L R\n", 'permutations of 4, #20');
is( `echo 4 dd bb aa cc | $solver 2>&1`, "cc F D R\n", 'permutations of 4, #21');
is( `echo 4 dd bb cc aa | $solver 2>&1`, "bb D R\n", 'permutations of 4, #22');
is( `echo 4 dd cc aa bb | $solver 2>&1`, "aa D R\n", 'permutations of 4, #23');

#       variations on a theme with 4 items ["aaaaa", "bbbb", "ccc", "dd"]
# force choice by string length
is( `echo 4 ccc dd aaaaa bbbb | $solver 2>&1`, "ccc L dd L\n", 'permutations of 4, #17');
is( `echo 4 dd bbbb aaaaa ccc | $solver 2>&1`, "ccc F D R\n", 'permutations of 4, #21');
is( `echo 4 bbbb aaaaa dd ccc | $solver 2>&1`, "bbbb D dd D\n", 'permutations of 4, #8');
is( `echo 4 bbbb dd aaaaa ccc | $solver 2>&1`, "dd L bbbb D\n", 'permutations of 4, #11');
is( `echo 4 ccc aaaaa dd bbbb | $solver 2>&1`, "ccc L dd L\n", 'permutations of 4, #14');
is( `echo 4 ccc dd bbbb aaaaa | $solver 2>&1`, "dd F R\n", 'permutations of 4, #18');
is( `echo 4 dd aaaaa ccc bbbb | $solver 2>&1`, "aaaaa L R\n", 'permutations of 4, #20');
is( `echo 4 dd bbbb ccc aaaaa | $solver 2>&1`, "ccc R D\n", 'permutations of 4, #22');
is( `echo 4 dd ccc aaaaa bbbb | $solver 2>&1`, "bbbb R D\n", 'permutations of 4, #23');

# identical items in list
is( `echo 2 aa aa | $solver 2>&1`, "\n", '1 repeat #1');
is( `echo 3 aa aa bb | $solver 2>&1`, "\n", '1 repeat #2');
is( `echo 3 aa bb aa | $solver 2>&1`, "aa F\n", '1 repeat #3');
is( `echo 3 bb aa aa | $solver 2>&1`, "aa R\n", '1 repeat #4');
is( `echo 4 aa cc bb aa| $solver 2>&1`, "aa L R\n", '1 repeat #5');
is( `echo 5 cc bb aa bb cc | $solver 2>&1`, "aa F cc L\n", '2 repeats');

#       "sad" path

# not explicitly excluded, so cover this case
#       exhaustive variations on a theme with 0 items []
is( `echo 0 | $solver 2>&1`, "\n", 'permutations of 0, #1');


#       "bad" path
# none!


exit 0;
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.