Równania zapałek


16

Twoim zadaniem w tym wyzwaniu jest przeanalizowanie danego „Równania zapałki” takiego jak to ...

wprowadź opis zdjęcia tutaj

... i dowiedzieć się, czy można go przekształcić w prawidłowe równanie poprzez zmianę kolejności dopasowań. Jeśli tak, musisz wypisać najmniejszą liczbę ruchów i wynikowe równanie.

Wejście

Dane wejściowe to ciąg znaków, który można odczytać ze STDIN, wziąć jako argument funkcji lub nawet zapisać w pliku. Jest to równanie reprezentujące układ zapałek i można je opisać za pomocą następującego 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 ;

Przykładem prawidłowego wejścia może być 3+6-201=0+0+8.

Zadanie

Rozważ następującą ilustrację, w której do każdej zapałki przypisany jest numer:

pozycje zapałek

Teraz mapujemy każdy symbol wejściowy na odpowiednie pozycje zapałek w następujący sposób:

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

Każdą formułę wejściową można przekształcić w układ zapałek. Na przykład staje się równanie „45 + 6 = 92”

wprowadź opis zdjęcia tutaj

gdzie niewykorzystane zapałki są wyszarzone. Twoim zadaniem jest znalezienie jak najmniejszej liczby zapałek, które należy zmienić, aby równanie było ważne.

Wynik

Rozróżniamy trzy możliwe przypadki:

  • Jeśli dane wejściowe są niepoprawne (tzn. Nie spełniają powyższego EBNF), wypisz wszystko, co chcesz.
  • W przeciwnym razie, jeśli istnieją sposoby na przekształcenie równania w poprawne poprzez zmianę kolejności zapałek, musisz podać zarówno minimalną liczbę przegrupowań, jak i odpowiednie równanie. Podobnie jak dane wejściowe, wyprowadzone równanie musi również spełniać dane EBNF. W powyższym przykładzie poprawnym wyjściem byłoby 1i 46+6=52. Jeśli istnieje wiele możliwości wynikowego równania, wypisz dowolną z nich.
  • W przeciwnym razie (więc jeśli dane wejściowe są prawidłowe, ale nie ma sposobu, aby równanie było prawdziwe), musisz wygenerować dane wyjściowe -1.

Detale

  • Nie możesz usuwać ani dodawać dopasowań. Oznacza to, że jeśli dane wejściowe są zbudowane z nzapałek, dane wyjściowe muszą również składać się z dokładnie nzapałek.
  • „Puste” bloki zapałek są dozwolone tylko na końcu i na początku równania, a nie w środku. Na przykład zamieniając się 7-1=6w7 =6-1 po prostu przez usunięcie -1z lewej strony i dodanie go po prawej stronie, w odległości 3 matchstick rearanżacji jest niedozwolone.
  • Ponieważ tak naprawdę nie postrzegam mapowania liczb na pozycje zapałek jako interesującą część tego wyzwania, dla ponad 20 bajtów możesz albo

    • uzyskać dostęp do pliku, w którym mapowanie (number/operation ↦ matchstick positions) jest przechowywane w dowolny rozsądny sposób, lub
    • jeśli Twój język programowania obsługuje Maptyp danych, załóż, że masz dostęp do mapy, która jest wstępnie zainicjalizowana za pomocą opcji -mapping (number/operation ↦ matchstick positions). Ta mapa może na przykład wyglądać tak:{(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})}

Przykłady

Wejście: 1+1=3Wyjście: 1 i1+1=2

Wejście: 15+6=21Wyjście: 0 i15+6=21

Wejście: 1=7Wyjście: -1

Wejście: 950-250=750Wyjście: 2 i990-240=750

Wejście: 1-2=9Wyjście: 1 i1+2=3

Wejście: 20 + 3=04Wyjście: cokolwiek

Zwycięzca

To jest , więc wygrywa najkrótsza poprawna odpowiedź (w bajtach). Zwycięzca zostanie wybrany tydzień po opublikowaniu pierwszej poprawnej odpowiedzi.


1
Proszę dodać 0: 1, 2, 3, 4, 5, 6dla zachowania spójności
nie że Charles

Dzięki, zupełnie jakoś o tym zapomniałem!
miernik

@vauge Hej, czy „2 = 1-1” -> „2-1 = 1” zwraca 3 lub 14 ruchów, ponieważ 2 technicznie trzeba przesunąć w lewo?
Cieric

@Cieric powinien zwrócić 3, po prostu dlatego, że możesz zmienić pozycję =(2 zapałek) i -(1 zapałkę) i pozostawić wszystkie cyfry tam, gdzie są. Gdyby jednak 2 musiały zostać przesunięte w lewo, należy również policzyć wymagane ruchy.
miernik

Czy istnieje ograniczenie liczby operacji? Czy dane wejściowe mogą być podobne 1+1+2=3-6+10? I to samo pytanie o wynik.
Qwertiy,

Odpowiedzi:


6

JavaScript, 1069 bajtów

Testowałem go z kilkoma równaniami testowymi i wydaje się, że teraz działa cały czas ...

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}

Cóż, to pierwszy raz, kiedy przesyłam odpowiedź, więc nie widzę, że wygrywam. Jest to w zasadzie metoda brutalnej siły, aby znaleźć wszystkie odpowiedzi, a następnie pobiera i zwraca najmniejsze z tablicy. pierwszy argument jest długością, a drugi tablicą z danymi wyjściowymi.

jeśli wejście to „1-2 = 9”, wyjście to [1, [„1 + 2 = 3”, „7-2 = 5”]]

a oto nieskompresowany 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;
}

Ostrzeżenie: nie rób równań takich jak 950-250 = 750, używa ~ 45 Matchsticks, a ponieważ ten kod używa brutalnej siły, spowoduje zawieszenie się javascript.


Wierzę, że możesz zadeklarować zmienne, których używasz, takie jak var kw pętlach, jako nieużywane parametry funkcji, oszczędzając 3 bajty dla każdej deklaracji.
rorlork

Myślę, że zamierzam nauczyć się kilku innych języków programowania i wymyślić nie tak brutalną siłę, aby spróbować naprawdę znokautować ten bajt odliczający.
Cieric

Myślę, że twoje rozwiązanie jest nieprawidłowe, ponieważ podczas obliczania odległości zawsze wyrównujesz znaki równości. W niektórych przypadkach nie jest to optymalny sposób. Na przykład „2 = 1-1” można przekształcić w 3 ruchach w „2-1 = 1”, a wyrównanie znaków „=” daje 14 ruchów. Nie widzę też, jak unikasz wiodących zer. Na przykład 08=8dla 80=8jest niepoprawne.
nutki

@nutki Tak, myślę, że mogę to zmienić. Myślałem, że to byłoby złe, ponieważ technicznie musicie przejść 2, aby zrobić miejsce dla -1
Cieric

@nutki ok, tak. Przepraszam, rozumiem teraz. Cóż, zamierzam naprawić wyrażenie regularne i sprawdzić, czy mogę zmienić kod dla odległości edycji.
Cieric

1

Perl, 334

Dość szybko, o ile rozwiązanie jest osiągalne w 1 lub 2 ruchach. Gdy nie ma rozwiązania, czeka cię długie oczekiwanie, nawet w najmniejszym przypadku 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}

Przykład:

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

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

Nie znajdzie to rozwiązań zmieniających długość równania, takich jak 11=4-> 2 11=11, ale nie jestem pewien, czy byłoby to dozwolone.


1
Rozwiązania zmieniające długość równania są dozwolone, o ile są zgodne z EBNF wymienionym w pytaniu. Dlatego powinny być również znalezione przez twoją funkcję.
miernik

@vauge, tak, widzę, że można to wywnioskować z sekcji „puste bloki machsticks” w szczegółach. Nie dodam go jednak do tego rozwiązania, ponieważ chociaż mogłoby to działać, sprawiłoby, że byłoby jeszcze wolniejsze.
nutki

@vauge Nie chcę brzmieć niegrzecznie, ale czy jeśli kod nie zostanie naprawiony, nadal będzie się liczył?
Cieric

@Cieric Jeśli nie ma innego rozwiązania, które obsługiwałoby wszystkie te przypadki, wówczas tak, to się liczy. Jeśli jednak do końca tego wyzwania będą jakieś w pełni działające odpowiedzi, zaakceptuję najkrótszą z nich.
miernik

@vauge dobrze sprawdzam tylko muszę się upewnić, że liczba ruchów jest prawidłowa do tej pory zawsze wyświetla prawidłowe równanie wyjściowe.
Cieric
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.