用(几乎)任何您喜欢的数字解方程


27

给定一串+=-至少包含一个字符的字符串,请=在所有符号之间以及在开头和结尾处插入正整数,以便满足数学方程式。

例如,给定输入

+-=-=

您需要像这样插入正整数A到F

A+B-C=D-E=F

这样等式都满足,即A + B - CD - EF都是相同的数字。

有许多可能的方法可以执行此操作,因为只要等式成立,就可以使用任何正整数集。这里的每一行都是可能输入的有效输出+-=-=

2+3-4=6-5=1
1+1-1=2-1=1
4+2-4=4-2=2
100+1-10=182-91=91
89+231-77=1024-781=243

请注意,表达式的值不需要像插入的数字一样为正整数。例如,给定输入-=-的输出1-10=8-17(从eval到-9)和10-1=17-8(从eval到9)都同样有效。当然,对于某些输入(例如,=不可能有负数的表达式),因为只能5=5插入正数之类的。

还要注意,零不是正整数。

以字节为单位的最短代码获胜。

您可以将数字输出为列表,而不是将其直接插入字符串中。如果确实输出字符串,则可能会有空格分隔符号和数字。因此,对于输入+-=-=,输出

2, 3, 4, 6, 5, 1

要么

2 + 3 - 4 = 6 - 5 = 1

相当于输出

2+3-4=6-5=1

测试用例

Input | One Possible Output
= | 1=1
== | 2=2=2
+= | 1+3=4
=+ | 2=1+1
-= | 30-10=20
=- | 1=2-1
=-= | 3=7-4=3
=+= | 2=1+1=2
=== | 100=100=100=100
+=- | 3+2=7-2
-=+ | 7-2=3+2
+=+ | 3+3=3+3
-=- | 1-10=8-17
--= | 60-1-1=58
++= | 60+1+1=62
-+= | 60-9+1=52
+-= | 60+9-1=68
+-=-= | 2+3-4=6-5=1
--=-- | 2-1-1=2-1-1
==-== | 47=47=50-3=47=47
=++=+-=-+=--= | 3=1+1+1=3+1-1=1-1+3=5-1-1=3
+--++-=-+-+- | 35+10-16-29+20+107-1000=5-4+3-2+1-876
====== | 8=8=8=8=8=8=8


我们可以假设公式长度的上限吗?
xnor

2
@xnor如果有帮助,您可以假定输入少于2 ^ 16个字符。
加尔文的业余爱好

Answers:


16

视网膜 58字节

[-+]
$&1
\B((\+1)|(-1))*
$._$*1$#3$*1$#2$*_$&
+`1_

1+
$.&

在线尝试!

在相同字节数下的替代解决方案:

((\+)|(-))*
$._$*1$#3$*1$#2$*_$&
+`1_

([+-])1*
$+1
1+
$.&

在线尝试!

说明

基本思想是将所有+s和-s简化为+1-1,然后添加足够大的数字以使所有方程式起作用。为了使方程式匹配,我们可以简单地在每个方程式之前添加相同的数字,然后对每个方程式减少一个,之后对每个方程式+1增加一个-1。由于我们将使用一元数,因此唯一需要注意的是第一个数必须足够大,这样我们才能将其减少一倍。

[-+]
$&1

我们先1-或之后插入一个+

\B((\+1)|(-1))*
$._$*1$#3$*1$#2$*_$&

\B确保这些比赛要么在输入的开始,或之间=+-,即所有在这里我们要插入表达式的数量领先的位置。的 ((\+1)|(-1))*一部分,那么只计算数量+1S和-1S IN组23分别。现在让我们分解一下替换字符串:

$._$*1   # For each character in the current string, insert a 1. This is
         # an offset which is the same for each expression and is guaranteed
         # to be large enough that all subsequent +1s can be cancelled.
$#3$*1   # For each -1, insert a 1.
$#2$*_   # For each +1, insert a _.
$&       # Re-insert the string of +1s and -1s.
+`1_

反复1_从字符串中删除,并从中应用所需的取消+1

1+
$.&

最后,将所有1s 字符串替换为它们的长度,以从一元转换为十进制。


8

Python 2,76个字节

lambda e:sum([[len(e+s)-2*s.count('+')]+[1]*len(s)for s in e.split('=')],[])

在线尝试!


3
您能补充说明吗?
加尔文的业余爱好

1
@HelkaHomba这个想法很简单:首先将输入的每个块均以等号分开。选择每个块的第一个数字eqtn_len + plus_signs + minus_signs - 2 * plus_signs = eqtn_len + minus_signs - plus_signs。然后,由于块中的所有其他数字均为1,因此该块的总数为eqtn_len + minus_signs - plus_signs - minus_signs + plus_signs = eqtn_len。方程的长度必须为正,因此一切都可行。
FryAmTheEggman

6

Python 2 199 179 178 172 162 158 156 152 151字节

太长了,但是解决方案很容易创建。

from itertools import*
i=input()
k='%s'
s=k+k.join(i)+k
for p in product(*[range(1,65537)]*-~len(i)):
    if eval((s%p).replace('=','==')):print s%p;break

在线尝试

这将尽一切可能,直到找到解决方案。该程序非常慢。它还在每次迭代时执行字符串替换。“ 172”编辑使其速度大大降低,因为它不是以较小的范围开始,而是以最大值开始。例如,输入-==+必须先尝试2 ** 32次尝试才能找到解决方案。

为了加快程序运行速度,请使用编辑历史记录中的178个字节的版本。


rangepython2中不是立即将整个范围创建为列表吗?IIRC您可以xrange改用它来加快速度,因为我认为这是延迟加载版本(Python3使用lazy作为默认加载版本range
Delioth

1
@Delioth使用另一个字节。目标是删除字节。而且,实际上并不能提供太多的提速,因为减慢的主要原因是迭代次数,而不是列表的创建,列表的创建只发生一次。我跑步print range(1,65537)并在0.034秒内完成。
mbomb007'3

好吧,当然,更多的是“这可能会使用完全相同的方法来加快速度”,这是因为它需要花费很长时间。内存跳动可能会导致严重的速度下降。另外,您可以通过不设置来减少一些字节(可能只有1个字节)l=...,而是将其放在product(range(...),repeat=len(s)+1)。如果你需要括号它不仅节省了一个字节(\ n)
Delioth

@Delioth即使我需要parens len(s)+1,我也可以-~len(s)改用,这不需要parens。
mbomb007'3

嗯对 我总是忘了按位操作和技巧-一定是前端javascript带来的麻烦正在占用我的Python专业知识!
迪洛斯(Delioth)

5

JavaScript(ES6),92 82字节

用@xnor的技巧欺骗了8个字节

let f =
x=>x.split`=`.map(q=>(x+q).length-2*~-q.split`+`.length+[...q,''].join(1)).join`=`
<input oninput="if(/^[+=-]+$/.test(value))O.innerHTML=f(value)" value="="><br>
<pre id=O>1=1</pre>

这里的技巧是1在每一个+或之后插入a -,然后在每个表达式前添加使表达式等于输入长度的数字。这样我们可以保证数字始终为正。由于=字符串中始终至少有1个,因此+s 的数量永远无法达到字符串的长度,因此余数始终至少为1。您可以通过在+上面的代码段中输入任意数量的s 来验证这一点。


5

Python 2中120个 119字节

-1字节归功于mbomb007

a=['1'+(n and('1'.join(n)+'1'))for n in input().split('=')]
print'='.join(`max(map(eval,a))-eval(c)+1`+c[1:]for c in a)

在线尝试!验证所有测试用例

首先,我将插入1每个位置,以检查最大值,然后将其添加为每个方程式的偏移量。这项工作是因为您无法添加负数,因此最小结果由+等式中仅具有的数量给出+


您可以删除几个空格。
mbomb007'3

5

GNU Prolog,156个字节

x(L,R,V)-->{E#>0},({L=[E|R],E=V};x(L,[E|R],X),("+",{V#=X+E};"-",{V#=X-E})).
q(L,R,V)-->x(L,T,V),({T=R};"=",q(T,R,V)).
s(Q,L):-q(L,[],_,Q,[]),fd_labeling(L).

说明

我们有很多方程需要求解,那么为什么不使用实际的方程求解器呢?

x基本上是形式方程的方程评估器+-+; 除了方程式本身之外,它还有两个附加参数(L,R包含方程式值的差异列表和V方程式求和的值)。正如序言往常一样,它可以使用任何方式轮(例如,你可以指定V并得到一个L,R,指定L,R并得到一个V,同时指定并验证值是否正确,或指定无论是在这种情况下,适当的约束将被放置在两个VL,R)。的“当前元素” L,R名为E,我们还包括一个断言,E大于0(因为该问题要求使用正数)。该函数比我想要的更为冗长,例如[E|R],由于列表是右相关的,而加法和减法是左相关的,因此我不得不编写两次模式匹配/不匹配。可悲的是,我们需要使用一个实际的列表,而不是从cons单元中发明我们自己的左关联列表类型,然后fd_labeling才能工作。

q与相似x,但也包含=。它基本上只是调用x,并且本身是递归的。顺便说一句,这是差异列表如何工作的非常清晰的演示,表明您可以将两个差异列表连接起来L,TT,R成为一个差异列表L,R。基本思想是差异列表是一个部分函数,​​它接受一个参数R并返回一个值L,该值R本身就是列表的前缀。因此,通过识别一个差异列表的自变量和另一个差异列表的返回值,我们可以组合这些函数,从而连接列表。

最后,,s它是实际上解决问题任务的功能,是一个q使用参数调用的包装函数。我们通过提供差值列表[]作为参数将其转换为常规列表,并用于fd_labeling查找所建立方程的解决方案。(默认情况下,如果没有必要将其设置为其他值,它似乎喜欢将值设置为1。但是,可以对其进行配置;value_method(random)比起将1放在各处,它提供了更多“有趣”的解决方案,而且仍然非常快。 )

样品输出

程序编写如下:

| ?- s("=++=+-=-+=--=", V).

V = [3,1,1,1,3,1,1,3,1,1,5,1,1,3] ?

如果我使程序更长一点,以添加一个value_method(random),结果会有所不同,但看起来像这样:

| ?- s("=++=+-=-+=--=", V).

V = [68,6,12,50,85,114,131,45,3,26,71,1,2,68] ? 

在两种情况下,?输出末尾的表示可能有多个解决方案。(当然,在这种情况下,我们知道,有一个很大不止一个解决方案!)


4

Mathematica,116个字节

Join@@(Prepend[#^2,1-Min[Tr/@c]+Tr@#]&/@(c=Characters@StringSplit["0"<>#<>"0","="]/."+"->-1/."-"->1/."0"->Nothing))&

将字符串作为输入并返回正整数列表的纯函数。基本策略:我们只加1减1,然后在每个表达式中选择初始数字以使所有内容相等。

c=Characters@StringSplit[#,"="]/."+"->-1/."-"->1将拆分在每个等号输入字符串,然后替换每个+通过-1和每个-通过1。但是,如果在开头或结尾有一个等号,那么它将被忽略。因此,我们在每个结尾("0"<>#<>"0")处人为地添加了一个新字符,并在字符串分割完成(/."0"->Nothing)之后使其消失。

现在,每个子列表的总数等于一个整数,我们可以将其放在+s和-s 前面以使每个表达式相等。1-Min[Tr/@c]是我们可以加到每个总数上的最小整数,以使它们全部为正。因此,Prepend[#^2,1-Min[Tr/@c]+Tr@#]&将每个子列表(将其^2所有条目都转为1)作为参数,并将其总偏移量乘以最小的补偿整数。将结果列表一起Join编辑以产生输出。


3

Ruby,76岁

->s{(?1+s.gsub(/./){|a|a+?1}).split(?=).map{|e|e[0]="#{5**8-eval(e)}";e}*?=}

由于5**8打高尔夫球,表达式的目标值固定为负1!最初我使用的是s.size+1负1。

取消测试程序

f=->s{(?1+s.gsub(/./){|a|a+?1}).           #add a 1 at the beginning and after every symbol
       split(?=).                          #split into an array of expressions at = signs
       map{|e|                             #for each expression string
         e[0]="#{5**8-eval(e)}";e          #change the first number to 5**8-eval(e)
       }*?=                                #and rejoin the strings
}


puts f["="] 
puts f["=="] 
puts f["+="] 
puts f["=+"]
puts f["-="]
puts f["=-"]
puts f["=-="]
puts f["=+="]
puts f["==="]
puts f["+=-"]
puts f["-=+"]
puts f["+=+"]
puts f["-=-"]
puts f["--="]
puts f["++="]
puts f["-+="]
puts f["+-="]
puts f["+-=-="]
puts f["--=--"]
puts f["==-=="]
puts f["=++=+-=-+=--="]
puts f["+--++-=-+-+-"]
puts f["======"]

输出量

390624=390624
390624=390624=390624
390623+1=390624
390624=390623+1
390625-1=390624
390624=390625-1
390624=390625-1=390624
390624=390623+1=390624
390624=390624=390624=390624
390623+1=390625-1
390625-1=390623+1
390623+1=390623+1
390625-1=390625-1
390626-1-1=390624
390622+1+1=390624
390624-1+1=390624
390624+1-1=390624
390624+1-1=390625-1=390624
390626-1-1=390626-1-1
390624=390624=390625-1=390624=390624
390624=390622+1+1=390624+1-1=390624-1+1=390626-1-1=390624
390624+1-1-1+1+1-1=390625-1+1-1+1-1
390624=390624=390624=390624=390624=390624=390624

2

PHP,207个 204 197 114字节

直接方法:更短,更快

foreach(explode("=",$argn)as$t)echo"="[!$c],strlen($argn)+($c=count_chars($t))[45]-$c[43],@chunk_split($t,!!$t,1);

在线运行echo '<input>' | php -nR '<code>'或对其进行测试

分解

foreach(explode("=",$argn)as$t) // loop through terms
    echo                            // print ...
        "="[!$c],                       // 1. "=" if not first term
        strlen($argn)                   // 2. maximum number
            +($c=count_chars($t))[45]   //    + number of "-"
            -$c[43],                    //    - number of "+"
        @chunk_split($t,!!$t,1);        // 3. each operator followed by "1"
  • !$c在第一次迭代中为true,将其强制转换1为字符串索引;"="[1]是空的。
    在那之后,$cset和!$cfalse 被设置为,0并且"="[0]是第一个字符。
  • 任何条款的最大值都不必超过加号+1;
    因此我们绝对保证输入长度的安全。所有条款都会对此进行评估。
  • chunk_split($s,$n,$i)$i在的每个$n字符后插入$s并在末尾。
    为防止空术语变为1,通过将块长度设置为来强制执行错误0

1

罗达112 110 109字节

f x{[(`:$x:`/"=")()|{|p|p~=":",""a=p;a~=`\+`,""b=p;b~="-","";["=",#x-#b+#a];{(p/"")|{|o|[o,"1"*#o]}_}}_][1:]}

在线尝试!

拆分功能未达到我在该程序中预期的效果。例如,split("", sep="")返回一个空字符串而不是空字符串。逻辑如何?因此,该程序比拆分语义理想时的程序要大近20个字节。

这个答案的想法是,我们知道输入字符串的长度必须大于或等于等式的值,因此我们将等式的值定义为字符串的长度。对于方程的每个部分,我们认为每个运算符+1-1,然后将其减去并加到方程的值中。

取消高尔夫:

function f(x) {
    /* Adds ":"s around the string to prevent "=" being split wrong. */
    [split(`:$x:`, sep="=") | for p do
        p ~= ":", ""          /* Removes colons. */
        a := p; b := p        /* Initializes a and b to be p. */
        a ~= "\\+", ""        /* The lengths of a and are now equal to the */
        b ~= "-", ""          /* numbers of "-" and "+" characters in x. */
        push("=", #x-#b+#a)   /* Prints "=" and the value of the equation */
                              /* minus number of "+"s plus number of "-"s. */
        split(p, sep="") | for o do /* For each operator: */
            push(o)                 /* Prints the operator. */
            push(1) if [o != ""]    /* Prints 1 unless the operator is "". */
        done
    done][1:] /* Removes the first character of the output ("="). */
}
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.