Kibrit çöpü denklemleri


16

Bu görevdeki göreviniz buna benzer bir "Kibrit çöpü Eşitliği" ni analiz etmektir ...

resim açıklamasını buraya girin

... ve maçları yeniden düzenleyerek geçerli bir denkleme dönüştürülüp dönüştürülemeyeceğini öğrenmek. Eğer öyleyse, bunu yapmak için en az sayıda hareket ve sonuçtaki denklemi çıkarmalısınız.

Giriş

Giriş, STDIN'den okunabilen, işlev bağımsız değişkeni olarak alınabilen veya hatta bir dosyada saklanabilen bir Dizedir. Bir kibrit çöpü düzenlemesini temsil eden bir denklemdir ve aşağıdaki EBNF kullanılarak açıklanabilir:

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

Geçerli bir giriş için örnek olarak gösterilebilir 3+6-201=0+0+8.

Görev

Her bir kibrit çöpünün atanmış bir numarası olduğu aşağıdaki çizimi düşünün:

kibrit çöpü pozisyonları

Şimdi her bir giriş sembolünü karşılık gelen kibrit çöpü konumlarıyla aşağıdaki gibi eşleştiriyoruz:

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

Her giriş formülü bir kibrit çöpü düzenlemesine dönüştürülebilir. Örneğin, "45 + 6 = 92" denklemi

resim açıklamasını buraya girin

kullanılmayan kibrit çubukları gri renkte görünür. Göreviniz, denklemi geçerli kılmak için yeniden düzenlenmesi gereken en az sayıda kibrit çöpü bulmaktır.

Çıktı

Üç olası durumu birbirinden ayırıyoruz:

  • Giriş geçerli değilse (yani yukarıdaki EBNF'yi karşılamıyorsa), ne istersen ver.
  • Kibrit yeniden düzenleyerek geçerli bir birine denklemi açmak için yollar vardır Aksi takdirde, sen çıkışına sahip her iki düzenlenmeleri minimum sayıda ve karşılık gelen denklem. Girdi gibi, çıkan denklem de verilen EBNF'yi karşılamalıdır. Yukarıdaki örnekte, doğru çıktı 1ve olacaktır 46+6=52. Elde edilen denklem için birden fazla olasılık varsa, bunlardan herhangi birini çıktılayın.
  • Aksi takdirde (giriş geçerliyse, ancak denklemi doğru yapmanın bir yolu yoksa) çıktı vermeniz gerekir -1.

ayrıntılar

  • Eşleşmeleri kaldırma veya ekleme izniniz yok. Bu, eğer giriş nkibrit çubuklarından yapılmışsa, çıktı da tam olarak nkibrit çubuklarından oluşmalıdır .
  • "Boş" kibrit çöpü bloklarına sadece denklemin sonunda ve başında izin verilir, ortada değil. Yani, örneğin, dönüm 7-1=6içine 7 =6-1basitçe kaldırarak -1sol taraftan ve sadece 3 kibrit çöpü yeniden düzenlemeleri içeren sağ tarafta eklemeden izin verilmez.
  • Gerçekten bir artı için, bu meydan ilginç bir parçası olarak konumlarını kibrit çöpü kadar numaralardan eşleme görmüyorum yana 20 bayt , şunlardan birini yapabilirsiniz

    • eşlemenin (number/operation ↦ matchstick positions)makul bir şekilde saklandığı bir dosyaya erişebilir veya
    • programlama diliniz bir Mapveri tipini destekliyorsa, -mapping ile önceden (number/operation ↦ matchstick positions)başlatılmış bir haritaya erişiminiz olduğunu varsayın. Bu harita örneğin şöyle görünebilir:{(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})}

Örnekler

Giriş: 1+1=3Çıkış: 1 ve1+1=2

Giriş: 15+6=21Çıkış: 0 ve15+6=21

Giriş: 1=7Çıkış: -1

Giriş: 950-250=750Çıkış: 2 ve990-240=750

Giriş: 1-2=9Çıkış: 1 ve1+2=3

Giriş: 20 + 3=04Çıkış: herhangi bir şey

kazanan

Bu , bu yüzden en kısa doğru cevap (bayt cinsinden) kazanır. Kazanan ilk doğru cevap gönderildikten bir hafta sonra seçilecektir.


1
Lütfen 0: 1, 2, 3, 4, 5, 6tutarlılık için ekleyin
Charles

Oh teşekkürler, bunu bir şekilde tamamen unuttum!
vauge

@vauge Hey '2 = 1-1' -> '2-1 = 1' 2 teknik olarak sola taşınmak zorunda kaldığı için 3 veya 14 hamle döndürmeli mi?
Cieric

@Cieric 3 döndürmelidir, çünkü =(2 kibrit çöpü) ve -(1 kibrit çöpü) konumunu değiştirebilir ve tüm numaraları oldukları yerde bırakabilirsiniz. Ancak, 2'nin sola taşınması gerekiyorsa, gerekli hamleleri de saymanız gerekir.
vauge

Operasyon sayısında bir sınırlama var mı? Girdi nasıl olabilir 1+1+2=3-6+10? Aynı soru çıktı.
Qwertiy

Yanıtlar:


6

Javascript, 1069 Bayt

Birkaç test denklemi ile test ettim ve şimdi her zaman çalışıyor gibi görünüyor ...

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}

Bu benim ilk kez bir cevap yolladığım, bu yüzden kendimi kazandığımı görmüyorum. Bu, temel olarak tüm cevapları bulmak için kaba bir yöntemdir ve daha sonra bir dizideki en küçükleri yakalar ve döndürür. ilk argüman uzunluk ve ikincisi çıktıları olan bir dizidir.

giriş "1-2 = 9" ise çıkış [1, ["1 + 2 = 3", "7-2 = 5"]]

ve işte sıkıştırılmamış kod:

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;
}

Uyarı: 950-250 = 750 gibi denklemler yapmayın ~ 45 Kibrit Çubuğu kullanır ve bu kod kaba kuvvet kullandığından javascript'in askıda kalmasına neden olur.


var kDöngülerde kullandığınız değişkenleri işleve kullanılmayan parametreler olarak bildirebileceğiniz ve her bildirim için 3 bayt tasarruf edebileceğinizi düşünüyorum.
rorlork

Sanırım birkaç programlama dili daha öğreneceğim ve bu bayt sayımını gerçekten düşürmek için o kadar kaba bir güç yolu bulamayacağım.
Cieric

Sanırım çözümünüz doğru değil, mesafeyi hesaplarken her zaman eşit karakterleri hizaladığınız gibi. Bazı durumlarda bu en uygun yol değildir. Örneğin '2 = 1-1' 3 hamlede '2-1 = 1' biçimine dönüştürülürken '=' işaretlerinin hizalanması 14 hamle verir. Ayrıca sıfırları nasıl önlediğini de göremiyorum. Örneğin 08=8için 80=8yanlıştır.
nutki

@nutki Evet, sanırım bunu değiştirebilirim. Teknik olarak -1
Cieric

@nutki tamam, evet. Üzgünüm, şimdi ne demek istediğini anlıyorum. Ben regex düzeltmek ve düzenleme mesafesi için etrafında kodu değiştirip değiştiremeyeceğim görmek.
Cieric

1

Perl, 334

Çözüme 1 veya 2 hamlede ulaşılabildiği sürece oldukça hızlı. Çözüm olmadığında, en küçük durumda bile uzun süre beklersiniz 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}

Misal:

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

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

Bu, denklemin uzunluğunu değiştiren çözümler bulamaz 11=4-> 2 11=11, ancak buna izin verileceğinden emin değilim.


1
Denklemin uzunluğunu değiştiren çözümlere, söz konusu EBNF'yi takip ettikleri sürece izin verilir. Bu nedenle, bunlar sizin fonksiyonunuz tarafından da bulunmalıdır.
vauge

@vauge, evet detaylarda "boş mafsal blokları" bölümünden çıkarılabildiğini görebiliyorum. Bu çözüme eklemeyeceğim, ancak çalışabilirken, daha da yavaşlatacaktır.
nutki

@vauge Kulağa kaba gelmek istemiyorum, ancak kod sabit değilse yine de sayılacak mı?
Cieric

@Cieric Tüm bu vakaları ele alan başka bir çözüm yoksa, evet, önemli olacaktır. Bununla birlikte, bu zorluğun sonunda tamamen çalışan cevaplar varsa , en kısalarını kabul edeceğim.
vauge

@vauge tamam sadece kontrol Sadece hareket sayısının doğru olduğundan emin olmak zorundayım, her zaman doğru çıkış denklemini görüntüler.
Cieric
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.