アンダーロード番号の最短表現


13

フレーバーテキスト

スタックベースのesolang Underloadは、関数型プログラミングといくつかの興味深い結びつきを持っています。それらの1つは、数値データ型の処理です。ラムダ計算のように、アクションをN回実行する関数によって自然数Nを表します。

物事を簡単にするために、Underloadコマンドの次のサブセットのみを考慮します。

  • : -このコマンドは、スタックの一番上のアイテムを複製します。
  • * - このコマンドは、単一の項目にスタックの一番上の二つのアイテムを連結します。

私たちは、定義過少数字Nを文字列として:*、実行した、スタックの一番上の項目を消費し、そのアイテムが一緒に連結さのn個のコピーを生成します。いくつかの例:

  • アンダーロードの数字0、-1、1 / 2、πはありません。
  • 空の文字列 は、スタックに手を付けないため、Underloadの数字1です。
  • :*それはトップ・アイテムを複製し、次に単一の項目にまとめ、それらの2つのコピーを連結しているため、不足負荷数字2:(A):*= (A)(A)*=(AA)
  • ::**アンダーロードの数字3です。(A)::**= (A)(A):**= (A)(AA)*= (AAA)です。
  • :::*** アンダーロードの数字4です。
  • :*:*また、アンダーロード数字4:(A):*:*= (AA):*= (AA)(AA)*= (AAAA)です。

一般に、MおよびNがアンダーロードの数字MおよびNである場合:N*、数字N + 1でありMN、数字M×N であることがわかります。

チャレンジ

あなたの仕事は、文字列としての入力に対してアンダーロード数値の最短表現を生成する最短プログラム(STDINで入力を取得する)または関数(引数で入力を取得する)を記述することです。つまり、入力が正の自然数N> 1である場合、文字の長さが他のすべてのアンダーロード数字N以下であるアンダーロード数字Nを生成する必要があります。

サンプルの入力と出力:( "Input- OUTPUT。")

  • 1-
  • 2- :*
  • 5- ::*:**(2×2 + 1)。
  • 7- ::*::***(2×3 + 1)または:::**:**(3×2 + 1)。
  • 33- ::*:*:*:*:**(2×2×2×2×2 + 1)。
  • 49- ::*:*:*:*::***(16×3 + 1、長さ14)ではなく::*::***::*::***(7×7、長さ16)。

入力が正の自然数でない場合、自由にエラーを返したり、未定義の動作を生成したり、終了することさえできません。提出物の答えを見つける方法の説明を歓迎します。

標準的な抜け穴の制限が適用されます。余分な入力、Webリクエスト、出力/戻り値は、:and *やなどの無限のランダムストリームではなく、正確に答えである必要があります。


@Geobits実行時間については何も言いませんでしたので、最終的に正しい答えが得られることを証明できる限り、あなたは大丈夫です。
algorithmshark 14

2
この問題は追加チェーンに関連しています。具体的には、入力の正解の長さx2*A117498(x)A117498が加算チェーンを見つけるためのバイナリとファクターメソッドの最適な組み合わせを与える場所です
ピーターテイラー14

回答:


4

GolfScript(61 60 55 54 53文字)

~:X'']({:A{.'.+'\*A{2$+}%~}%}*{,}${1\~X=}?{44/'*:'=}%

これは私の以前のバージョンよりもトリッキーではなく、少し異なるアプローチを取りますが、それでも総当たりです。私たちはそれ':'X*'*'X*+が候補解であることを知っているので、その長さまですべてのバランスのとれた文字列を生成し、正しいものに評価される最も短いものをとると、確実に見つけることができます。

# Evaluate input and store the target number in X
~:X
# Seed the generator with the empty string
'']
# X times...
({
    # Store the array of strings so far into A
    :A
    # Generate A' by mapping each element
    {
        # Dup: this leaves an untouched copy of the current string
        .
        # Wrap the duplicate in .+
        '.+'\*
        # For each element in A, generate that element suffixed with the current string
        A{2$+}%~
    }%
}*
# Order by length
{,}$
# Find the first element which evaluates to X
{1\~X=}?
# tr .+ :*
{44/'*:'=}%

ハワードのおかげで、その解決策から、1文字の微調整をいくつか盗まれました。


ハハ、3の入力はWebインタープリターで実行するのに3秒以上かかります。最高級のゴルフ。
algorithmshark 14

@algorithmshark、重複排除のスポットでかなり高速化できます。挿入.&だけで内側のループ後(すなわち間~}%}*
ピーター・テイラー

4

GolfScript(54 53文字)

これは、ハワードの精神(正しい値に評価する文字列を構築し、正しい値に評価する文字列を見つけるために候補文字列を総当たりするのではなく、最短の文字列を選択する)の精神に基づいたアプローチですが、私は思う別の答えに属します。

~.''':*':s@,{):x,2>{:^~$x^/~$+{s\*}x^%*}%{,}$0=}/]((=

バグの多いバージョンのインタープリターを実行するため、オンラインデモは利用できません。

# Let <N> denote the string which evaluates to N
# We want to enter the main loop with three values on the stack: <0> <1> <2>
# However, we'll never use <0>, so we can actually replace that with any value at all.
# Getting the input from underneath 3 items would normally use two stack manipulations.
# Trick: let's use the input value for <0>! (This gives a further bonus later).
# NB We store the value of <2> in the variable s
~.''':*':s@
# for x=1 to input_value ...
,{):x
    # for ^=2 to x-1 ...
    ,2>{:^
        # Use negative stack offsets to index the stack from the start
        # I.e. -1$ gets the first item on the stack, which is <0>
        # -2$ gets the second item on the stack, which is <1>
        # In general, val~$ gets <val>
        ~$x^/~$+
        # We have the string <^><x / ^> on the stack.
        # Increment it (x % ^) times to get a candidate <x>.
        {s\*}x^%*
    }%
    # Select a shortest string.
    {,}$0=
}/
# Group the stack into one array and select the appropriate offset,
# reusing that hacky <0> substitute for the offset.
]((=

エラーが発生しない場合は、(スタックに何も残さないという事実を利用して)3+と置き換えることで、1つを剃ることができます。)[]0=[]2>
ピーターテイラー14

[]2>[]エラーなしで収量。
ハワード14

@Howard、ああ、golfscript.apphb.com 古いバージョンを実行している必要があります。しかし、その置換はinputに対して間違った出力を取得するため、間違っていたことがわかります'1'
ピーターテイラー14

((=代わりに修正できます-1=
ハワード14

そして、golfscript.apphb.comは実際に古いバージョンを実行しますがネストされたループの例は機能しません。
ハワード14

4

Pythonの2.7 - 87 84 92

u=lambda n:n>1and min([u(i)+u(n/i)for i in range(2,n)if n%i<1]+[':'+u(n-1)+'*'],key=len)or''

説明:
これは非常に簡単なソリューションです。nの可能なすべての表現を2つの数値の積またはとして再帰的にテストし:(n-1)*、最小長の解を見つけます。range(2、n)は再帰が深さを制限するために必要であり、n <2は基本ケースを与えます。

注:
iとn / iは、nの2つの要因です。...の...および...または...の置換... if ... else ...は、 ''がfalseと評価されるため機能しません。文字列の最小値は、最も短い文字列の1つを示します。Python 2.7では、//の代わりに/を使用して1文字を保存します。

編集:ベースケースを式の後ろに移動し、...および...または...を使用して、いくつかのスペースを削ることができました。

テストケース:

u(1)
''
u(5)
'::*:**'
u(49)
'::*:*:*:*::***'

1
" 文字列の最小値は最短の文字列の1つを与える "は、オプションの引数を指定しない限り真ではないkey=len。これは、辞書的に最も早い文字列を提供します。()。以来'*' < ':'、この手段あなたは2のべき乗を含むソリューションへのバイアスを持っているが、彼らは常に最短であることを?
ピーターテイラー14

1
回答:実際にはバイアスはより複雑ですが、常に正しい答えを与えるとは限りません。最小の反例はでありu(33)、辞書式にソートすると14文字になります::**::*::*:***が、長さでソートすると12文字になります::*:*:*:*:**
ピーター・テイラー

1
Pythonの文字列比較について、私はそれを知りませんでした。回答を更新しました。
isaacg 14

3

GolfScript、63 58 56文字

~n./\{:v~[':*'1$*v,,2>{v,\%!},{.v=v,@/v=+}/]{,}$0=]}*-2=

コードはSTDINで入力を受け取り、結果を出力します。

例:

> 49
:::**:*:*:*:**

> 1234
::::*:*:*:**:*:*:**::**::***

独自のケースをオンラインでテストできます


うわー、ファクタリングベースのアプローチは、ブルートフォースアプローチよりもかなり長くなると思いました。
ピーターテイラー14

@PeterTaylor私もそう思ったが、そうではないことが判明した。さらに、私のブルートフォースソリューションはあなたのものより少し長かったです;-)
ハワード14

各部分が何をするのか説明していただけますか?:x(=少しだけフォローアップできます。また、妥当な時間内に49を実行できるため、+ 1。
algorithmshark 14

@algorithmshark私はまだ解決に取り組んでいるので、それはまだ(ちょうどそうであったように)まだ大きく変わるかもしれません。主に、一部はx,2>{x\%!},、すべての真の約数を与えx{.v=x@/v=+}/その後のためのソリューションを連結dし、x/dすべての除数のためにd{,}$長さでそれらをソートし0=、それらの最短(および最初の:(x-1)*ケース)を取ります。
ハワード

2

Brachylog 2、30(最終的には26)バイト、言語の延期の課題

以下は、現在のBrachylog 2実装で機能する関数です(現在の実装では文字列処理に問題があるため、文字コードのリストを返します)。

∧.l∧?{ḋp~c×ᵐ{-₁↰₁:[42,58]c↻}ᵐc}

オンラインでお試しください!

言語はまだ非常に新しいです。以下は、仕様に従って動作するはずの26バイトバージョンのプログラムですが、実装されていない機能を使用しているため、まだ有効ではありませんが、将来的には使用される可能性があります(さらに効率が低下します):

{ḋp~c×ᵐ{-₁↰₁:"*:"c↻}ᵐc}ᶠlᵒh

説明

∧.l∧?{ḋp~c×ᵐ{-₁↰₁:[42,58]c↻}ᵐc}
∧.l∧?                            Evaluation hint: try shortest outputs first
     {                        }  Define an inner function
      ḋ                          Prime factor decomposition of the input
       p                         Find a permutation
        ~c                       Find an inverse concatenation (i.e. partition)
          ×ᵐ                     Take the product of each set inside the partition
      ḋp~c×ᵐ                     Find a decomposition into factors ≥ 2
            {              }ᵐ    For each of those factors:
             -₁                  Decrement it
               ↰₁                Call the inner function recursively
                 :[42,58]c       Append "*:" (as character codes)
                          ↻      Move the last element to the start
                             c   Append the results together

基本的な考え方はかなり単純です:数を(1以上の)因子に分解する(必ずしも素因数である必要はありませんが、1の因子は許可されません)と、それらのそれぞれを1 +(再帰から得られる表現)コール)。これにより、数の可能なすべてのアンダーロード表現を検索することが保証されます(3つ以上の数を乗算することで乗算行を「連続して2回」適用し、乗算する乗算段でそれらを分離することで行を2回インクリメントします)一緒に1つの数字)。1を素因数に分解すると空のリストが得られるため、明示的なベースケースは必要ありません。したがって、ゼロの数を乗算する乗算ステージでそれを構築します。

特に、私が与えた評価順序のヒント(最終的な出力のサイズに関して最短から最長の回答を生成する)は、質問の「最短」の部分を解決するという点ではそれほど優れていないため、プログラムはかなり非効率的です。実際にプログラムを迅速に完了する(はるかに有用なヒントは、「各再帰段階で最短の回答のみを生成する」ですが、それはより多くのバイトを必要とします...)さらに、ḋp~c×ᵐ乗算パーティションをそれぞれ数回生成することができ、プログラムに多くの冗長な作業をさせます。


0

J-81文字

後世のために、これは私がJでできることで最高でした。

_2{::(0&(][,0{<@;"1@({~#(#~]-:"1<.)@(],.%)2}.i.@#)(/:#&>)@,':'<@,'*',~>@{:),~)&a:

結果のリストを作成し、0(使用されていない)と1を表す2つの空の文字列(,~and a:)で始まり&、次に次の番号の最短表現を追加する動詞(フック、トレイン、およびsneickの使用)を繰り返します。

反復する実際の動詞は、リストの長さを操作対象の番号の指標として使用します。まず、この数を因子のペアに因数分解し(#(#~]-:"1<.)@(],.%)2}.i.@#)、配列からプルすることで各ペアを取得します({~)。これらのペアのそれぞれ(数が素数の場合は0になる可能性があります)を単一の文字列(<@;"1)に変換します。

その後、我々はそのリストに囲ま前の結果のエントリを追加する:*、長さによってソートこのリスト((/:#&>))。最後に、このリストから最初の結果を取得し(0{)、ベース配列の最後に追加します([,)。ループの反復が完了すると、入力から長さ2のリストが0から始まります。したがって、最後から2番目の文字列(_2{::)を返す必要があります。

   un =: _2{::(0&(][,0{<@;"1@({~#(#~]-:"1<.)@(],.%)2}.i.@#)(/:#&>)@,':'<@,'*',~>@{:),~)&a:
   un 49
::*:*:*:*::***
   un 1234
:*::*:*:*::*::***::*::*:****
   un 10010
:*::*:*::***::*:*:*:*:*:*:*::***
   2 * (1 + 3 * 2^2) * (1 + 3 * 2^7)
10010
   6!:2 'un 10010'   NB. time in seconds
19.5539

0

Jelly、33バイト、言語のポストデートチャレンジ

ÆḌḊµ⁹÷Ñ;Ñð€
’ß”:;;”*W;ÇLÞḢµ“”>1$?

オンラインでお試しください!

簡単なブルートフォースソリューション。

説明

主なプログラム

’ß”:;;”*W;ÇLÞḢµ“”>1$?
              µ  >1$?  If input is greater than 1, then:
’ß                       Run recursively on the input - 1
  ”:;                    Prepend a colon
     ;”*                 Append an asterisk
        W;               Cons to:
          Ç                the result of the helper, on {the original input}
           LÞ            Sort by length
             Ḣ           Take the first (i.e. shortest) result
               “”      Otherwise, return an empty string

メインプログラムは、ヘルパー関数を使用して、乗算によって値を生成するすべての可能な方法を列挙し、加算によって値を生成しようとし、最短の可能性を返します。また、基本ケース(の入力1)ます。

ヘルパー機能

ÆḌḊµ⁹÷Ñ;Ñð€
ÆḌ µ     ð€            For all proper factors of the input
  Ḋ                    except the first (i.e. 1):
    ⁹÷                   Divide it into the input;
      Ñ                  Run the main program on it;
       ;                 Append the result of:
        Ñ                  the main program run on {the factor}

ヘルパー関数は、入力を2つの数値の乗算として表現するすべての可能な方法を試行し、最短の表現を取得するために相互再帰的にメインプログラムを呼び出します。


0

GNU Prolog、96バイト

v(N)-->{N#=1};{N#=A*B,A#<B,B#<N},v(A),v(B);{N#=M+1},":",v(M),"*".
s(N,S):-length(S,_),v(N,S,[]).

最初の行は、Underload評価を実装する文法であり、逆方向に動作します(実際には、A#<B制約のために順方向には動作しませんA#<N。双方向で動作する低速のプログラムに変更してください)。2行目は、関数のような述語を定義しますs(このプログラムの解決策として実装される関数)を入力として与えられた数に評価される最短の文字列を見つけます(これは、比較的単純なタスクではイライラさせられますが、それはあなたのためのプロローグです...)。

プログラムは、仕様を文法に直接変換し、その後Prolog構文に直接変換することを考えると、かなり自明なはずです。定義は、vそれが言うN空の文字列は1であり、又はNあるA× B(とA未満B未満N)と、文字列がの連結であるv(A)v(B)、またはNでありM+ 1列である:と連結「Sは、いくつかの長さを有する」とは、しかしこれを行の最初に指定することは、Prolog実装へのヒントとして機能し、最初に最短の長さをチェックする必要があります(つまり、戻り値の最短長を取得することを意味します)。v(M)と連結します*。2行目は少し微妙です。length(S,_)

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