Konwertuj 1 na dowolną dodatnią liczbę całkowitą, używając tylko operacji * 3 i / 2

11

Dowolną dodatnią liczbę całkowitą można uzyskać, rozpoczynając od 1 i stosując sekwencję operacji, z których każda albo „pomnóż przez 3”, albo „podziel przez 2, odrzucając resztę” .

Przykłady (pisanie f dla * 3 ig dla / 2):

4 = 1 *3 *3 /2 = 1 ffg
6 = 1 ffggf = 1 fffgg
21 = 1 fffgfgfgggf

Napisz program o następującym działaniu:

Dane wejściowe : dowolna dodatnia liczba całkowita, poprzez stdin lub na stałe. (W przypadku zakodowania na stałe, numer wejściowy zostanie wykluczony z długości programu.)
Wyjście : ciąg znaków f i g taki, że <input> = 1 <string>(jak w przykładach). Taki ciąg w odwrotnej kolejności jest również dopuszczalny. NB: Dane wyjściowe zawierają tylko f i g lub są puste.

Zwycięzcą jest pozycja z najmniejszą liczbą bajtów programu plus wyjście, gdy 41 to wejście.

res
źródło
1
Skąd wiesz, że to prawda?
marinus
@ marinus uważa się, że to prawda (ale jeszcze nie udowodniono). szukam jakiegoś dowodu.
Fabinout,
@ marinus, możesz udowodnić, że jest to możliwe poprzez zejście (lub równoważnie przez silną indukcję). Podział na x mod 3przypadki: jeśli x=3yskonstruuj y, a następnie zastosuj f; jeśli x=3y+1skonstruuj 2y+1i zastosuj, fto g; jeśli x=3y+2to się komplikuje, ale zasadniczo jest rekurencyjne.
Peter Taylor,
Na osobnej uwadze, czy dane wyjściowe muszą być w kolejności aplikacji, czy też kolejność kompozycji może być akceptowalna?
Peter Taylor,
@PeterTaylor Tak czy inaczej jest OK.
res

Odpowiedzi:

3

GolfScript, wynik 64 (43-2 + 23)

0{)1.$2base:s{{3*}{2/}if}/41=!}do;s{103^}%+

(41 jest zakodowane, więc -2 znaki dla wyniku). Dane wyjściowe to

fffgffggffggffgggffgggg

który ma 23 znaki (bez nowej linii). Dzięki konstrukcji kod gwarantuje, że zawsze zwraca (jedną z) najkrótszych reprezentacji.

Howard
źródło
Cytując użytkownika Darrena Stone'a w sugerowanej edycji tego postu: „Nie mogę tu zostawić komentarza, więc zostawiam edycję. Ten wynik nie zawiera dwóch pierwszych znaków„ 1 ”, ani też nie ma ich odzwierciedlenia w wyniku. Powinien być łatwa naprawa i wciąż niezwykle krótkie rozwiązanie. Na zdrowie! ” (Odrzuciłem, ale pomyślałem, że powinienem nieść wiadomość)
Klamka
@Doorknob Wyzwanie stanowi, że "1 "nie należy go włączać do wyniku.
Howard,
3

Brudzimy się, przyjaciele!

JAWA 210 207 199 znaków

public class C{public static void main(String[] a){int i=41;String s="";while(i>1){if(i%3<1){s+="f";i/=3;}else if(i%3<2){s+="g";i+=i+1;}else{s+="g";i+=i+(Math.random()+0.5);}}System.out.println(s);}}

nie golfa:

public class C {

    public static void main(String[] a) {

        int i = 41;
        String s = "";
        while (i > 1) {
            if (i % 3 == 0) {
                s += "f";
                i /= 3;
            } else {
                if (i % 3 == 1) {
                    s += "g";
                    i += i + 1;
                } else {
                    s += "g";
                    i += i + (Math.random() + 0.5);
                }
            }
        }
        System.out.println(s);
    }
}

wyjście: w zależności od wiary starych bogów, najkrótszy miałem 30. Zauważ, że wynik musi być odczytany z prawej strony.

234

1 ggfgfgfgfggfggfgffgfggggfgffgfggfgfggggfgffgfggfgfggfgfggfgfgggggfffgfggfgfggfgfgggffgggggfffgfggggfgffgfggfgfggfgfggfgfggfgfggfgfggfgfggggfgffgfggfgfggfgfggfgfggfgfggfgfggggggggggggfgfgfggggfgfgfggfffgfgfggffgfgfggfgfggggffgfgfffff

108

1 gggffgfgfggggggfggggfgffggggfgfgfgfgfgffgggfgggggfggfffggfgfffffgggffggfgfgggffggfgfgggffggggggfgfgffgfgfff

edycja 45

1 ggfgfgfgfgggfggfffgfggfgfgggggggffgffgfgfff

punkty: 318 199 + 30 = 229

edycja1 (2 * i + 1)% 3 == 0 -> (2 * i)% 3 == 1

Nota Bene, jeśli używasz Java 6, a nie Java 7 podczas gry w golfa, możesz użyć

public class NoMain {
    static {
        //some code
        System.exit(1);
    }
}

Struktura 39 znaków zamiast standardowej struktury o długości 53 znaków.

Fabinout
źródło
(2*i+1)%3==0jest równoważny zi%3==1
Howard
Tak to jest. dzięki
Fabinout,
if(X){A}else{if(Y){B}else{C}}jest dłuższy niż if(X){A}else if(Y){B}else{C}. Możesz także zastąpić swoje ==warunki krótszymi <.
Peter Taylor,
@PeterTaylor prawda, moje rozwiązanie jest nadal brzydkie. Nie wiem, czy część losowa powoduje, że kod jest krótszy, ale na pewno sprawia, że ​​wyjście jest gorsze.
Fabinout,
Twoje ciągi f / g zaczynają się od „g” (co powinno oznaczać „/ 2”), więc przekonwertują 1 na 0 zamiast na 41. Zmiana f na g i odwrotnie, również nie wydaje się dać 41.
res
3

Python, wynik 124 (90-2 + ​​36)

x=41;m=f=g=0
while(3**f!=x)*(m!=x):
 f+=1;m=3**f;g=0
 while m>x:m/=2;g+=1
print'f'*f+'g'*g

90 znaków kodu (nowe wiersze jako 1 każdy) - 2 dla zakodowanych cyfr wejściowych + 36 znaków wyjściowych

Wynik:

ffffffffffffffffgggggggggggggggggggg
Darren Stone
źródło
1
Jeśli tak m=f=0, możesz wykonać zewnętrzną pętlę while(n!=x)*(m!=x)i usunąć przerwy. Daje to 95 znaków kodu.
Daniel Lubarov
@Daniel: Pan jest dżentelmenem i uczonym. Dzięki! Twoje zgłoszenie jest wciąż bezpieczne 10 znaków przede mną. :)
Darren Stone
1
Możesz dodatkowo trochę zaoszczędzić, jeśli zastąpisz wszystko nprzez 3**f.
Howard,
1
Dla input = 1 twój program generuje błąd („nazwa 'g' nie jest zdefiniowana”, z powodu nie wchodzenia w zewnętrzną pętlę while).
res
1
Możesz wyciąć inną postać, pisząc print'f'*f+'g'*g, co dałoby wynik 90-2 + ​​36 = 124.
res
3

Python, wynik 121 (87-2 + 36)

t=bin(41)
l,n,f=len(t),1,0
while bin(n)[:l]!=t:f+=1;n*=3
print(len(bin(n))-l)*'g'+f*'f'
Daniel Lubarov
źródło
@Darren, nie byłem pewien, jak interpretować opis wyjściowy, ale prawdopodobnie masz rację. Dodałem „1”. Dzięki!
Daniel Lubarov,
1
Możesz upuścić „1” (ponownie!) Oryginalna interpretacja opisu wyniku była poprawna. Jeszcze raz ciesz się przywództwem w Pythonie! :-)
Darren Stone
1
Jeśli połączone swoją 2, 3 i 4. linie do l,n,f=len(t),1,0, i usunięto '1',z instrukcji print, Twój wynik będzie 87-2 + 36 = 121.
res
Dzięki chłopaki - upuściłem 1,. l,n,f=len(t),1,0daje taką samą liczbę znaków, prawda? (Dla każdej zmiennej an =i nowa linia są zastępowane dwoma ,s.)
Daniel Lubarov,
Jeśli każda nowa linia ma jeden znak (np. LF w stylu UNIX), wówczas wersje jedno- i trzywierszowe mają tę samą długość. Jeśli każda nowa linia składa się z dwóch znaków (np. CR + LF w stylu MS Windows), wówczas wersja jednowierszowa jest o dwa znaki krótsza niż wersja trzywierszowa. Wynik 121 zakłada, że ​​znaki nowego znaku są jednoznakowe.
res
1

Perl, wynik 89 (63-2 + 28)

$_=41;$_=${$g=$_%3||$_==21?g:f}?$_*2+$_%3%2:$_/3while$_>print$g

Przypuszczenie: jeśli naiwne podejście opisane w moim oryginalnym rozwiązaniu poniżej osiągnie cykl, cykl ten wyniesie [21, 7, 15, 5, 10, 21, ...] . Ponieważ nie ma kontrprzykładów dla 1 ≤ n ≤ 10 6 , wydaje się to prawdopodobne. Aby to udowodnić, wystarczyłoby wykazanie, że jest to jedyny cykl, który może istnieć, co mogę, ale nie muszę, zrobić w późniejszym czasie.

Powyższe rozwiązanie pozwala uniknąć cyklu natychmiast, zamiast zgadywania (błędnie) i unikania go za drugim razem.

Wyjście (28 bajtów):

ggfgfgfgfggfggfgfgfggfgfgfff

Perl, wynik 100 (69-2 + 33)

$_=41;1while$_>print$s{$_=$$g?$_*2+$_%3%2:$_/3}=$g=$_%3||$s{$_/3}?g:f

Korzystanie z metody zgadywania i sprawdzania. Łańcuch jest konstruowany przy użyciu operacji odwrotnych (konwersja wartości na 1 zamiast na odwrót), a łańcuch zostaje odpowiednio dublowany, co jest dozwolone w specyfikacji problemu.

Za każdym razem, gdy napotkamy nie wielokrotność trzech, zostanie ona pomnożona przez dwa, dodając jeden, jeśli wynik będzie wielokrotnością trzech. Kiedy napotkamy wielokrotność trzech, zostanie ona podzielona przez trzy ... chyba że wcześniej ta wartość została napotkana, co wskazuje na cykl, a więc zgadnij i sprawdź.

Wyjście (33 bajty):

ggfgfgfgfggfggfgffgfgggfggfgfgfff
primo
źródło
1

J, wynik 103 (82–2 + 23)

* Uwaga: Nazwałem swoje czasowniki fi g, nie należy mylić ich z ciągami wyjściowymi fi g.

Mocno zakodowane:

f=:3 :'s=.1 for_a.y do.s=.((<.&-:)`(*&3)@.a)s end.'
'gf'{~#:(>:^:(41&~:@f@#:)^:_)1

Funkcje ogólne:

f=:3 :'s=.1 for_a.y do.s=.((<.&-:)`(*&3)@.a)s end.'
g=:3 :'''gf''{~#:(>:^:(y&~:@f@#:)^:_)1'

Zrezygnowałem z operowania na blokach liczb binarnych, co było najważniejszą zmianą w zakresie kompaktowania g. Zmieniłem nazwy zmiennych i usunąłem trochę białych znaków, ale wszystko funkcjonalnie jest takie samo. (Zastosowanie: g 41)

J, wynik 197 (174 + 23)

f =: 3 : 0
acc =. 1
for_a. y do. acc =. ((*&3)`(<.&-:)@.a) acc end.
)

g =: 3 : 0
f2 =: f"1 f.
l =. 0$0
i =. 1
while. 0=$(l=.(#~(y&=@:f2))#:i.2^i) do. i=.>:i end.
'fg'{~{.l
)

Wynik: ffffffffggggggggfgffggg

fkonwertuje listę wartości logicznych na liczbę, używając 0 jako *3i 1 jako /2(i floor). #:i.2^itworzy tablicę rangi 2 zawierającą wszystkie tablice boolowskie rangi 1 o długości i.

rationalis
źródło