仅用0-9和四个运算符来表示数字


14

说明

Befunge是使用stack的二维程序。

这就是说,做5 + 6,你写56+,意思是:

56+
5    push 5 into stack
 6   push 6 into stack
  +  pop the first two items in the stack and add them up, and push the result into stack

(to those of you who do not know stacks, "push" just means add and "pop" just means take off)

但是,正如您所知,我们无法将数字56直接推入堆栈。

要做到这一点,我们必须写78*相反,它乘78和将产品推入堆栈。

细节

输入可以采用任何格式,这取决于程序员可以决定是否使用STDIN。

输入将是一个正整数(包含0或不包含负整数将没有加分)。

输出将是仅包含以下字符的字符串:(0123456789+-*/不会使用%模数。)

目标是使用上述格式找到可以表示输入的最短字符串。

例如,如果输入为123,则输出为67*99*+。应该从左到右评估输出。

如果有一个以上可接受的输出(例如99*67*+,也是可接受的),则可以打印任何输出(打印所有输出均无奖金)。

进一步说明

如果您仍然不了解如何67*99*+评估123,这是详细的说明。

stack    |operation|explanation
          67*99*+
[6]       6         push 6 to stack
[6,7]      7        push 7 to stack
[42]        *       pop two from stack and multiply, then put result to stack
[42,9]       9      push 9 to stack
[42,9,9]      9     push 9 to stack
[42,81]        *    pop two from stack and multiply, then put result to stack
[123]           +   pop two from stack and add, then put result to stack

TL; DR

程序需要使用上面指定的格式找到可以表示输入(数字)的最短字符串。

笔记

这是一个挑战,因此以字节为单位的最短代码获胜。

消歧

-可以是x-yy-x,在程序员的自由裁量权。但是,选择必须在解决方案内保持一致。同样的/

样例程序

Lua,1862个字节(在线尝试

因为我是作者,所以我不会打高尔夫球。

说明:

This uses the depth-first search method.

有关深度优先搜索的更多信息:此处

该程序:

local input = (...) or 81

local function div(a,b)
    if b == 0 then
        return "error"
    end
    local result = a/b
    if result > 0 then
        return math.floor(result)
    else
        return math.ceil(result)
    end
end

local function eval(expr)
    local stack = {}
    for i=1,#expr do
        local c = expr:sub(i,i)
        if c:match('[0-9]') then
            table.insert(stack, tonumber(c))
        else
            local a = table.remove(stack)
            local b = table.remove(stack)
            if a and b then
                if c == '+' then
                    table.insert(stack, a+b)
                elseif c == '-' then
                    table.insert(stack, b-a)
                elseif c == '*' then
                    table.insert(stack, a*b)
                elseif c == '/' then
                    local test = div(b,a)
                    if test == "error" then
                        return -1
                    else
                        table.insert(stack, a+b)
                    end
                end
            else
                return -1
            end
        end
    end
    return table.remove(stack) or -1
end

local samples, temp = {""}, {}

while true do
    temp = {}
    for i=1,#samples do
        local s = samples[i]
        table.insert(temp, s..'0')
        table.insert(temp, s..'1')
        table.insert(temp, s..'2')
        table.insert(temp, s..'3')
        table.insert(temp, s..'4')
        table.insert(temp, s..'5')
        table.insert(temp, s..'6')
        table.insert(temp, s..'7')
        table.insert(temp, s..'8')
        table.insert(temp, s..'9')
        table.insert(temp, s..'+')
        table.insert(temp, s..'-')
        table.insert(temp, s..'*')
        table.insert(temp, s..'/')
    end
    for i=1,#temp do
        if input == eval(temp[i]) then
            print(temp[i])
            return
        end
    end
    samples = temp
end

奖金

如果您使用Befunge(或它的任何变体)编写代码,这对您来说是小菜一碟。


3
给定答案,可能很难确定它是否总是产生最排序的字符串。一个想法是生成一个很大的集合,比如说30--50个数字,并根据所有输出字符串长度的总和进行评分。但是,我不确定如何将该分数与代码长度结合起来
Luis Mendo

4
子集。
Addison Crump

2
聊天中复制我的想法:“我想过,但我认为该子集使事情变得简单得多,因为1)没有十六进制,2)没有浮点,3)没有重复和4)仅是肯定的”
Sp3000

1
@CoolestVeto这个区别足以使旧答案无效。
Rɪᴋᴇʀ

1
@CoolestVeto我认为另一个挑战应该作为与此挑战的副本来解决。
mbomb007 '16

Answers:


4

Python 2,278字节

我最好的解决方案,每次都会给出最短的答案。(但很慢)

def e(c):
 s=[];x,y=s.append,s.pop
 while c:
  d,c=c[0],c[1:]
  if"/"<d<":":x(d)
  else:a,b=y(),y();x(str(eval(b+d+a)))
 return int(y())
def g(v):
 s="0123456789+-*";t=list(s)
 while 1:
  for x in t:
   try:
    if e(x)==v:return x
   except:0
  t=[x+y for x in t for y in s]

Python 2,437字节

该解决方案更长,但是非常快(不是蛮力)。而且我很确定,它总是返回最短的结果。

r=range;l=len;a=input()
def f(n):
 if n<=9:return str(n)
 for d in r(9,1,-1):
  if n%d==0:return f(n/d)+"%d*"%d
 h=sum(map(int,list(str(n))))%9
 return f(n-h)+"%d+"%h
m={x:f(x) for x in r(a*9)}
for b in m:
 if a-b in m and l(m[b])+l(m[a-b])+1<l(m[a]):m[a]=m[a-b]+m[b]+"+"
 if a+b in m and l(m[b])+l(m[a+b])+1<l(m[a]):m[a]=m[a+b]+m[b]+"-"
 if b!=0 and a%b==0 and a/b in m and l(m[b])+l(m[a/b])+1<l(m[a]):m[a]=m[a/b]+m[b]+"*"
print m[a]

2
欢迎来到PPCG!希望您在这里过得愉快。
Leaky Nun

1
@pbochinak我想我可能已经找到了一个有效的。f(6551)返回25*8*9*7+9*8+(13个字符),而9999***52*-(11个字符)则更好。通过eval上面的我自己的功能进行了验证(在问题中)。
Leaky Nun

4
@pbochniak正如我之前的评论所指出的,此答案在当前状态下无效。建议您在进行修订时暂时将其删除(如果没有其他选择,以防止其引起负面投票)。
丹尼斯

1
您的时间可能只是while c:
2016年

您可以使用;将变量的分配(将字节保存在缩进的块中)分开,ven的技巧,消除符号和其他任何内容之间的空格,然后t可以执行。
CalculatorFeline

4

Perl中,134个 133 132 128字节

包括+5 -Xlp(另外2个,因为代码包含'

在STDIN上运行目标编号:

perl -Xlp befour.pl <<< 123

befour.pl

@1{1..9}=1..9;$.+=2,map{for$a(%1){"+-*/"=~s%.%"\$1{\$-=$a$&$_/'$1{$a}$1{$_}$&'=~/^.{$.}\$/}||=\$&"%eegr}}%1until$\=$1{$_}}{

它没有人为的限制,并且从概念上讲有点有效,但是运行时间却很糟糕,尽管我牺牲了一些字节来加快速度。在我的系统上,生成长度为11的解决方案(例如目标编号6551)大约需要5个小时。

多牺牲7个字节可以使速度更可承受。

@1{1..9}=1..9;$.+=2,map{for$a(@a){"+-*/"=~s%.%"\$1{\$-=$a$&$_/'$1{$a}$1{$_}$&'=~/^.{$.}\$/}||=\$&"%eegr}}@a=keys%1until$\=$1{$_}}{

长度为11的溶液17分钟,长度为13的溶液约5小时。需要长度15的第一个数字是16622,大约需要2天。需要长度17的第一个数字是73319。

注意,它假定除法通过向0截断来返回整数(根据befunge 93规范)


美元符号有什么作用?(我一点也不讲Perl)
Leaky Nun

1
@KennyLau $访问标量值。a=4perl将在大多数语言中您将要编写的地方使用$a=4。但也可用于更复杂变量的标量访问。例如,$a{$b}从哈希(地图,字典)获取%a键入的标量值$b
Ton Hospel

2

C,550个 545字节

#define L strlen
#define y strcpy
#define t strcat
char c[9999][99];i=1,k=3;main(j){for(;i<10;i++)*c[i]=i+'0';for(;k--;){
for(i=1;i<9999;i++)for(j=1;j<=i;j++)*c[i]&&*c[j]&&(i+j>9998||*c[i+j]&&
L(c[i+j])<L(c[i])+L(c[j])+2||t(t(y(c[i+j],c[i]),c[j]),"+"),
i*j>9998||*c[i*j]&&L(c[i*j])<L(c[i])+L(c[j])+2||t(t(y(c[i*j],c[i]),c[j]),"*"));
for(i=9999;--i;)for(j=i;--j;)*c[i]&&*c[j]&&(*c[i/j]&&
L(c[i/j])<L(c[i])+L(c[j])+2||t(t(y(c[i/j],c[i]),c[j]),"/"),
*c[i-j]&&L(c[i-j])<L(c[i])+L(c[j])+2||t(t(y(c[i-j],c[i]),c[j]),"-"));}
scanf("%d",&i);printf("%s",c[i]);}

550个 545字节(预处理指令毕竟但三个新行)删除不必要的换行之后。

@Kenny Lau-它可以接收1到9998之间的整数作为输入,但是我认为计算出最优解的输入范围小于9998。另一方面,如果内存较大,则可以扩展两个范围允许它。

该程序不能将大于9998的任何数字压入堆栈。(可以修改9998。)我以另一版本运行该程序,在外循环(带有k的那个循环)上迭代,只要有任何数字的改进在1到9998之间(按照Dijkstra的算法)。经过三轮迭代后,没有任何改善。因此,为了节省字节,我将k = 3硬编码。

要扩大范围,需要做两件事-修改常量9999和9998,在有改善的情况下,在变量外循环上以可变的迭代次数运行它,以查看直到没有改善发生的时间,然后将常数k = 3修改为该值。


欢迎来到PPCG!希望您在这里过得愉快。
Leaky Nun

这完美地通过了我的6551测试。该计划的有效范围是多少?
尼姑

我相信它是9999。能否将这些信息添加到您的解决方案中?
尼姑

它应该是9998此外,还可以通过初始化吃一些字节ijkmain()
Leaky Nun

1
@Kenny Lau-谢谢您的编辑。关于扩大范围,我注意到扩大范围实际上还需要一点时间。我将这些信息包括在答案中。
mIllbyte

2

Python 2,284字节

免责声明:永远为某些值抓狂……但确保始终返回最短的字符串,并且没有人为施加的范围限制……甚至适用于负值。:)

def f(v):
 i,z=0,'+-*/'
 while 1:
  s=('%x'%i).translate(__import__('string').maketrans('abcd',z),'ef');t=s;q=[];a,p=q.append,q.pop;i+=1
  try:
   while t:
    o,t=t[0],t[1:]
    if o in z:n,m=p(),p();a(eval(`m`+o+`n`))
    else:a(int(o))
   if p()==v and not q:return s
  except:pass

算法:

  • 从...开始 i = 0
  • 取代表的十六进制值的字符串i,并替换abcd+-*/分别,并删除任何ef
  • 尝试将字符串作为后缀表示法(RPN)处理
  • 如果成功,并且结果与输入值匹配,则返回使用的字符串。
  • 否则,增加并重i试。

“ [t]永远获得某些价值”您是否测试过?有什么价值?
Leaky Nun

@KennyLau我只是写了一个测试,计算真实f(i)0 <= i <= 6551(捕捉6551你使用无效@pbochniak的最初提交值)。现在,它只运行了几分钟,这是测试的最后输出: 91 : 49+7* 3.020 s (total 108.174 s, worst 89: 5.827 s) 更新-它刚刚完成,值92: 92 : 149+7*+ 258.761 s (total 366.935 s, worst 92: 258.761 s)
Ken'Joey'Mosher

@KennyLau:测试已经运行了一个多小时,并且只有达到最高标准113…… 如果您有兴趣,请参见此处的完整测试输出(pastebin) ...
Ken'Joey'Mosher

2

Python 2,182字节

n=input()
L=[[[],""]]
while 1:
 s,c=L.pop(0);L+=[[s+[i],c+`i`]for i in range(10)]+(s[1:]and[[s[:-2]+[eval(`s[-2]`+o+`s[-1]`)],c+o]for o in"/+-*"[s[-1]==0:]])
 if[n]==s[-1:]:print c;E

太慢了,我已经让它在输入上运行了一个小时221,但仍然没有终止。造成这种缓慢的主要原因是,我将列表用作广度优先搜索的队列,并且.pop(0)是列表的队列O(n)

L 只是一个包含 (stack, code to reach stack)成对。在每个步骤中,始终添加数字,并且如果堆栈中至少有两个元素,则执行运算符。仅当最后一个元素不为0时才执行除法,尽管我强烈怀疑永远不需要除法(尽管我没有办法证明除法,但我已经检查了是否达到500)。

NameError最终打印结果后,程序通过a终止。


到底;E在做什么?
Leaky Nun

@KennyLau这是NameError终止的步骤,因为E在其他任何地方均未定义
Sp3000,2016年

哇真聪明
Leaky Nun

1

CJam,79岁

ri:M;A,:s:L;{L2m*{s,Y=},{~:A+AS*~!"/+-*">\f{\+}~}%Y2+:Y;_L@+:L;{S*~M=},:R!}gR0=

在线尝试

这是非常低效的,但是只要有足够的内存和时间,它最终就可以工作。123的16GB内存不足,但是120和125可以。


1

Pyth-35个字节

蛮力。奇怪的是,新的隐式输入实际上损害了我的分数,因为它似乎对.v也 pyth_eval。

.V1IKfqQ.x.v+jd_T\;N^s+"+-*/"UTbhKB

在这里在线尝试


0

Python 3,183个字节

e,n=enumerate,input()
v=list('0123456789')+[' '*n]*n*2
for i,s in e(v):
 for j,t in e(v):
  for o,k in zip('+*-',(i+j,i*j,i-j)):
   if 9<k<2*n:v[k]=min(v[k],s+t+o,key=len)
print(v[n])

速度并非完全不合理(以秒或分钟为单位完成123、221、1237、6551)。更改该if语句可以if j<=i and <k<2*n加快速度,但需要增加9个字节。我省略了除法(/),因为我看不到它是如何需要的。


提示:需要分裂。
Leaky Nun
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.