欠载数的最短表示


13

风味文字

基于堆栈的esolang 欠载有一些有趣的联系,函数式编程。其中之一是对数值数据类型的处理-像lambda演算一样,您可以通过执行N次操作的函数来表示自然数N。

为简单起见,我们仅考虑以下Underload命令子集:

  • : -此命令复制堆栈上的顶层项目。
  • * -此命令将堆栈中的前两个项目合并为一个项目。

我们将一个Underload数字N定义为一个字符串,当执行该字符串时:*它消耗堆栈中的最高位项目,并产生N个该项目的副本,并将它们连接在一起。一些例子:

  • 没有欠载数字0,-1、1 / 2,π。
  • 空字符串是欠载数字1,因为它使堆栈保持不变。
  • :*是欠载数字2,因为它复制了最上面的项目,然后将这两个副本连接在一起成为一个项目:(A):*= (A)(A)*= (AA)
  • ::**是Underload数字3:(A)::**= (A)(A):**= (A)(AA)*= (AAA)
  • :::*** 是欠载数字4。
  • :*:*也是欠载数字4:(A):*:*= (AA):*= (AA)(AA)*= (AAAA)

通常,您会发现,如果MN分别是欠载数字M和N,则:N*数字N + 1和MN数字M×N。

挑战

您的任务是编写最短的程序(在STDIN上接受输入)或函数(通过参数接受输入),以产生最短的欠载数字表示形式,作为字符串输入。也就是说,如果输入的正自然数N> 1,则必须生成一个负数N,其字符长度小于或等于其他所有负数N的长度。

输入和输出示例:(“输入- 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关于执行时间,我什么也没说,所以只要您能证明它最终会给出正确的答案,就可以了。
algorithmhark

2
这个问题与加成链有关。具体而言,输入正确答案的长度x2*A117498(x)其中A117498给出的二进制和因子的方法的最佳组合查找一个加法链。
彼得·泰勒

Answers:


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解释器上执行。最好的高尔夫。
algorithmhark

@algorithmshark,您可以通过重复数据删除来相当快地提高速度。插入.&只是内部循环后(即间~}%}*
彼得·泰勒

4

GolfScript(54 53个字符)

这种方法符合霍华德(Howard's)的精神(构建评估为正确值的字符串并选择最短的字符串,而不是通过候选字符串进行蛮力查找来评估为正确值的字符串),但我认为它与众不同它属于一个单独的答案。

~.''':*':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+)(利用[]0=没有在堆栈上留下任何东西的事实)来刮胡子,如果这不是[]2>导致错误的话。
彼得·泰勒

[]2>产量[]没有错误。
霍华德

@Howard,啊,golfscript.apphb.com 必须正在运行旧版本。但是事实证明我错了,因为替换导致输入的输出错误'1'
彼得·泰勒

您可以使用((=而不是进行修复-1=
霍华德

并且golfscript.apphb.com确实运行旧版本,嵌套循环示例不起作用。
霍华德

4

蟒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''

说明:
这是一个非常简单的解决方案。它以两个数字的乘积或as递归地测试n的所有可能表示形式:(n-1)*,然后找到最小长度的解决方案。range(2,n)是必需的,以便递归具有一定的深度,并且n <2给出基本情况。

注意:
i和n / i是n的两个因子。...和...或...替换...如果... else ...不起作用,因为''的计算结果为false。字符串的最小值给出了最短的字符串之一。Python 2.7通过使用/而不是//保存1个字符。

编辑:将基本情况移到表达式的后面,使我可以使用...和...或...并刮除几个空格。

测试用例:

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

1
串分给最短的字符串中的一个 ”,除非你提供可选参数是不正确的key=len。它是字典上最早的字符串。(示例)。因为'*' < ':'这意味着您偏向于包含2的幂的解,但是它们总是最短的吗?
彼得·泰勒

1
答:偏见实际上更为复杂,但并非总是能给出正确的答案。最小的反例是u(33),按字典顺序排序为14个字符,::**::*::*:***但按长度排序为12个字符::*:*:*:*:**
Peter Taylor

1
我对Python字符串比较一无所知。我已经更新了答案。
isaacg 2014年

3

GolfScript,63 58 56个字符

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

该代码在STDIN上输入并打印结果。

例子:

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

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

您可以在线测试自己的案例。


哇,我认为基于分解的方法要比蛮力方法长很多。
彼得·泰勒

@PeterTaylor我也这么认为,但事实并非如此。而且,我的蛮力解决方案比您长一些;-)
Howard

您介意解释每个部分的作用吗?我只能跟进直到:x(=。另外,+ 1表示能够在合理的时间内运行49。
algorithmhark

@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 +之间进行交替(从递归获得的表示形式)呼叫)。这样可以确保搜索所有可能的欠载表示形式(我们可以通过将两个以上的数字相乘来应用“连续两次”的乘法阶段,并通过将它们乘以一个相乘的乘法来连续两次使用递增阶段)只是一个数字)。我们不需要显式的基本情况,因为将1分解为素数因子会得到一个空列表,因此,我们使用将零数字相乘的乘法阶段来构造它。

该程序效率很低,尤其是因为我给出的评估顺序提示(就最终输出的大小而言,生成的答案从最短到最长)在解决问题的“最短”部分时,并不是那么好实际上使程序迅速完成(一个更有用的提示是“在每个递归阶段仅生成最短的答案”,但这需要更多的字节…)。此外,ḋp~c×ᵐ每次可以生成多次乘法分区,从而使程序可以做很多多余的工作。


0

J-81个字符

对于后代来说,这是我在J语言中能做的最好的事情。

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

我们创建一个结果列表,以两个表示0(从未使用过)和1的空字符串(分别是,~a:)开头,然后在其上迭代一个动词(鬼hook地使用钩子,trains和&),该动词附加下一个数字的最短表示形式。

我们迭代的实际动词使用列表的长度作为我们对哪个数字进行操作的指标。首先,我们将此数字分解为成对的因子(#(#~]-:"1<.)@(],.%)2}.i.@#),然后通过从数组({~)中提取来检索每一对。我们将这些对中的每对(如果数字为质数,则可能为0)变成单个字符串(<@;"1)。

然后,在该列表的后面追加前一个结果的条目,并用:和括起来*,并按长度((/:#&>))对列表进行排序。最后,我们从列表(0{)中获得第一个结果,并将其附加到基本数组([,)的末尾。当循环完成迭代后,我们将得到一个比输入长2的长度列表,从0开始。因此,我们要返回的是倒数第二个字符串(_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

果冻,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}

helper函数尝试使用所有可能的方法将输入表示为两个数字的乘积,并相互递归调用主程序以获取其最短表示形式。


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,[]).

第一行是一种语法,它实现欠载评估,并且在相反的方向上起作用(实际上,由于A#<B受到约束,它在向前的方向上并不完全起作用;将其更改A#<N为慢速程序,可以双向运行)。第二行定义了类似函数的谓词s(这是作为该程序的解决方案实现的函数),该谓词找到了可能的最短字符串,该字符串的值计算为作为输入的给定数字(这对于一个相对简单的任务来说非常令人费解,但是那是给您的序言...)。

该程序应该是相当不言自明的,因为它或多或少是将规范直接翻译成语法,然后是Prolog语法。的定义是v说,N在空字符串中为1,或者NA× BA小于B小于N),并且字符串为v(A)and 的串联v(B),或者NM+ 1,并且字符串:v(M)串联*。第二行有点微妙;length(S,_) 表示“ S有一定的长度”,但是将其指定为行中的第一件事是Prolog实现的提示,即它应首先检查最短的长度(这意味着我们将获得返回值的最短长度) 。

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.