火柴方程


16

在此挑战中,您的任务是像这样分析给定的“火柴方程”。

在此处输入图片说明

...并通过重新排列匹配项来找出是否可以将其转换为有效方程。如果这样,您将输出最少的移动次数以及由此产生的方程式。

输入值

输入是一个字符串,可以从STDIN读取,可以作为函数参数,甚至可以存储在文件中。它是代表火柴棍排列的方程式,可以使用以下EBNF进行描述:

input = term, "=", term ;
term = number | (term, ("+" | "-"), term) ;
number = "0" | (numeralExceptZero , {numeral}) ;
numeralExceptZero = "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;
numeral = "0" | numeralExceptZero ;

有效输入的示例为3+6-201=0+0+8

任务

考虑下图,其中每个火柴杆都分配了一个数字:

火柴棍的位置

现在,我们将每个输入符号映射到相应的火柴棍位置,如下所示:

0 ↦ 1,2,3,4,5,6
1 ↦ 4,5
2 ↦ 2,3,5,6,8
3 ↦ 3,4,5,6,8
4 ↦ 1,4,5,8
5 ↦ 1,3,4,6,8
6 ↦ 1,2,3,4,6,8
7 ↦ 4,5,6
8 ↦ 1,2,3,4,5,6,8
9 ↦ 1,3,4,5,6,8
- ↦ 8
+ ↦ 8,10
= ↦ 7,9

每个输入公式都可以变成火柴棍排列。例如,等式“ 45 + 6 = 92”变为

在此处输入图片说明

未使用的火柴杆显示为灰色的地方。您的任务是找出必须重新排列以使方程有效的最少数量的火柴。

输出量

我们区分三种可能的情况:

  • 如果输入无效(即不满足上述EBNF),则输出所需的任何内容。
  • 否则,如果有办法通过重新排列火柴棍把方程变成一个有效的,你必须输出两个重排的最小数量相应的方程。正如输入一样,输出方程也必须满足给定的EBNF。在上面的示例中,正确的输出为 146+6=52。如果所得方程式有多种可能性,请输出其中任何一种。
  • 否则(因此,如果输入有效,但无法使方程式成立),则必须输出-1

细节

  • 您无权删除或添加匹配项。这意味着,如果输入由n火柴棍构建,则输出也必须完全由n火柴棍组成。
  • “空”火柴棍块仅允许在方程式的结尾和开头,而不能在中间。因此,例如,把7-1=67 =6-1通过简单地移除-1从左侧和增加它的右侧只有3火柴重排是不允许的。
  • 由于我并没有真正看到从数字到火柴棍位置的映射是此挑战的有趣部分,因此,加上20个字节,您可以

    • 访问(number/operation ↦ matchstick positions)以任何合理方式存储映射的文件,或者
    • 如果您的编程语言支持Map数据类型,请假定您有权访问使用(number/operation ↦ matchstick positions)-mapping预先初始化的映射。例如,此地图可能如下所示:{(0,{1,2,3,4,5,6}),(1,{4,5}),(2,{2,3,5,6,8}),(3,{3,4,5,6,8}), ..., (-,{8}),(+,{8,10}),(=,{7,9})}

例子

输入: 1+1=3输出: 11+1=2

输入: 15+6=21输出: 015+6=21

输入: 1=7输出: -1

输入: 950-250=750输出: 2990-240=750

输入: 1-2=9输出: 11+2=3

输入: 20 + 3=04输出:任何

优胜者

这是,因此最短的正确答案(以字节为单位)获胜。在第一个正确答案发布后的一周内,将选择获奖者。


1
请添加0: 1, 2, 3, 4, 5, 6以保持一致性
并非Charles

哦,谢谢,完全以某种方式忘记了!
vauge 2015年

@vauge嘿,“ 2 = 1-1”->“ 2-1 = 1”应该返回3或14步,因为从技术上讲2必须左移?
Cieric

@Cieric它应该返回3,这仅仅是因为您可以切换=(2个火柴)和-(1个火柴)的位置并将所有数字保留在原来的位置。但是,如果必须向左移动2,则还必须计算所需的移动。
vauge 2015年

操作次数是否有限制?输入可以像1+1+2=3-6+10吗?关于输出的同样问题。
Qwertiy

Answers:


6

Javascript,1069字节

我已经用很多测试方程式对其进行过测试,现在看来它一直在工作……

function w(t){function B(c,f){d=(c.length>f.length?f:c).split("");e=(c.length>f.length?c:f).split("");longer=Math.max(d.length,e.length);if(0!==d.length&&0!==e.length){c=[];for(x in d)for(y in c[x]=[],e)c[x][y]=1<y-x?-1:function(c,n){r=0;for(j in n)-1<c.indexOf(n[j])&&r++;return c.length+n.length-2*r}(a[d[x]],a[e[y]]);return v=function(f,n){for(var h=f.length-2;0<=h;h--)c[n.length-1][h]+=c[n.length-1][h+1];for(h=f.length-2;0<=h;h--)for(var q=0;q<n.length-1;q++)1>=h-q&&(c[q][h]+=-1==c[q][h+1]?c[q+1][h+1]:Math.min(c[q+1][h+1],c[q][h+1]));return c[0][0]/2}(e,d)}return-1}a=[[1,2,3,4,5,6],[4,5],[2,3,5,6,8],[3,4,5,6,8],[1,4,5,8],[1,3,4,6,8],[1,2,3,4,6,8],[4,5,6],[1,2,3,4,5,6,8],[1,3,4,5,6,8]];a["+"]=[8,0];a["-"]=[8];a["="]=[7,9];a[" "]=[];l=0;p=[];u=[];r=/^([1-9]\d*|0)([+-]([1-9]\d*|0))*=([1-9]\d*|0)([+-]([1-9]\d*|0))*$/;b=/(=.*=|[+=-]{2,}|^[+=-])/;if(!t.match(r))return-1;g=function(c,f,t){if(0===t&&f.match(r)&&eval(f.replace("=","==")))c.push(f);else for(var n in a)t>=a[n].length&&" "!=n&&!(f+n).match(b)&&g(c,f+n,t-a[n].length)};g(p,"",function(c){m=0;for(var f in c)m+=a[c[f]].length;return m}(t.split("")));for(var z in p)k=B(t,p[z]),u[k]||(u[k]=[]),u[k].push(p[z]);for(var A in u)return[A,u[A]];return-1}

好吧,这是我第一次提交答案,所以我看不到自己赢。这基本上是一种蛮力方法,可以找出所有答案,然后获取并返回数组中最小的答案。第一个参数是长度,第二个参数是带有输出的数组。

如果输入为“ 1-2 = 9”,则输出为[1,[“ 1 + 2 = 3”,“ 7-2 = 5”]]

这是未压缩的代码:

function ms(s) {
a=[[1,2,3,4,5,6],[4,5],[2,3,5,6,8],[3,4,5,6,8],[1,4,5,8],[1,3,4,6,8],[1,2,3,4,6,8],[4,5,6],[1,2,3,4,5,6,8],[1,3,4,5,6,8]];
a["+"] = [8, 0];
a["-"] = [8];
a["="] = [7, 9];
a[" "] = [];
l = 0;
p = [];
u = [];
r = /^([1-9]\d*|0)([+-]([1-9]\d*|0))*=([1-9]\d*|0)([+-]([1-9]\d*|0))*$/;
b = /(=.*=|[+=-]{2,}|^[+=-])/;
if (!s.match(r)) return -1;
function f(g,h)
{
    d=(g.length>h.length?h:g).split('');
    e=(g.length>h.length?g:h).split('');
    longer=Math.max(d.length, e.length);
    if(0!==d.length&&0!==e.length)
    {
        g=[];
        for(x in d)
        {
            g[x]=[];
            for(y in e)
            {
                g[x][y]=(y-x>1)?-1:function(g, h){r=0;for(j in h)if(g.indexOf(h[j])>-1)r++;return g.length+h.length-2*r;}(a[d[x]],a[e[y]]);
            }
        }
        v=function(d,e)
        {
        for(var y=d.length-2;y>=0;y--) g[e.length-1][y]+=g[e.length-1][y+1];
        for(var y=d.length-2;y>=0;y--)
            for(var x=0;x<e.length-1;x++)
                if(y-x<=1)
                    g[x][y]+=g[x][y+1]==-1?g[x+1][y+1]:Math.min(g[x+1][y+1], g[x][y+1]);
        return g[0][0]/2}(e,d)
        return v
    }
    return -1;
}
g=function(n, s, i){if (i===0 && s.match(r) && eval(s.replace('=','=='))){n.push(s);return;}for (var c in a) if(i>=a[c].length && c!=" " && !(s+c).match(b)) g(n, s+c, i-a[c].length);};
g(p, "", function(q){m=0;for(var t in q)m+=a[q[t]].length;return m}(s.split('')));
for (var i in p)
{
    k=f(s, p[i]);
    if (!u[k]) u[k] = [];
    u[k].push(p[i]);
}
for (var q in u) return [q, u[q]];
return -1;
}

警告:请勿执行类似950-250 = 750的方程式,它使用〜45个火柴棍,并且由于此代码使用了蛮力,因此会导致javascript挂起。


我相信您可以var k将循环中使用的变量声明为该函数的未使用参数,从而为每个声明节省3个字节。
rorlork 2015年

我想我将去学习更多的编程语言,并找出一种不太蛮力的方法来尝试真正减少该字节数。
Cieric

我认为您的解决方案是不正确的,因为在计算距离时,您总是将等号字符对齐。在某些情况下,这不是最佳方法。例如,“ 2 = 1-1”可以转换为3个动作,变成“ 2-1 = 1”,而对齐“ =”符号则可以进行14个动作。我也看不出如何避免前导零。例如08=8对于80=8是不正确的。
nutki

@nutki是的,我想我可以改变这一点。我想这是错的,尽管由于您在技术上必须移至2号才能为-1

@nutki好的,是的。对不起,我明白你的意思了。好吧,我将修复正则表达式,看看是否可以更改代码的编辑距离。
Cieric

1

Perl,334

只要解决方案以1或2步即可达到,速度就相当快。如果没有解决方案,即使是最小的情况,您也要等待很长时间1=7

#!perl -p
@y=map{sprintf"%010b",$_}63,24,118,124,89,109,111,56,127,125,64,192,768;
$y{$z{$y[$c++]}=$_}=$y[$c]for 0..9,qw(- + =);
$"="|";$l=s/./$y{$&}/g;$x{$_}=1;for$m(0..y/1//){
last if$_=(map"$m $_",grep{s/@y/$z{$&}/g==$l&&/^\d.*\d$/&!/\D\D/&!/\b0\d/&y/=//==1&&eval s/=/==/r}keys%x)[0];
$_=-1;s/0/"$`1$'"=~s!1!$x{"$`0$'"}=1!ger/eg for keys%x}

例:

$ time perl ~/matchstick.pl <<<950-250=750
2 990-250=740

real    0m39.835s
user    0m39.414s
sys 0m0.380s

这不会找到像11=4-> 这样改变equasion长度的解决方案2 11=11,但是我不确定是否可以这样做。


1
只要遵循问题中提到的EBNF,就可以更改方程长度的解。因此,它们也应该通过您的功能找到。
vauge 2015年

@vauge,是的,我可以看到它可以从详细信息中的“空铁棍块”部分中推断出来。我不会将其添加到此解决方案中,尽管它虽然可以工作,但会使其变慢。
nutki 2015年

@vauge我不想听起来很粗鲁,但是如果代码不固定,它还会计数吗?
Cieric 2015年

@Cieric如果没有其他解决方案可以处理所有这些情况,则可以,它将计算在内。但是,如果在挑战结束之前有任何可行的答案,我将接受其中最短的答案。
vauge 2015年

@vauge好的,只需检查一下,我只需要确保移动数正确即可,所以它始终显示正确的输出方程式。
Cieric
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.