Die minimale Fibonacci-Herausforderung!

19

Herausforderung

In dieser Aufgabe würden Sie eine ganze Zahl N (weniger als 10 6 ) erhalten, um herauszufinden, wie Sie mit Fibonacci-Zahlen mindestens zu N summieren können. Diese Partition wird als Zeckendorf-Darstellung bezeichnet .

Sie können jede Fibonacci-Zahl mehr als einmal verwenden und wenn es mehr als eine Repräsentationsausgabe gibt.

Wenn die Eingabe beispielsweise 67 ist, könnte eine mögliche Ausgabe die Fibonacci-Zahlen 1,3,8,55 verwenden, was auch die minimale Anzahl von Fibonacci-Zahlen ist, die verwendet werden können, um die Summe 67 zu erhalten .

Der Eingang N steht in einer einzigen Zeile, die Eingänge werden mit EOF abgeschlossen.

Beispiele

Im Format angegeben input: output

0: 0
47: 34+13
3788: 2584+987+144+55+13+5
1646: 1597+34+13+2
25347: 17711+6765+610+233+21+5+2
677: 610+55+8+3+1
343: 233+89+21
3434: 2584+610+233+5+2

Einschränkungen

  • Die Anzahl der Eingänge würde 10 6 Werte nicht überschreiten .
  • Ihr Programm sollte für alle Eingaben nicht länger als 5 Sekunden ausgeführt werden.
  • Sie können jede Sprache Ihrer Wahl verwenden.
  • Kürzeste Lösung gewinnt!
Quixotic
quelle
"Sie könnten jede Fibonacci-Nummer ..." wie? "Die Anzahl der Eingaben würde 10 ^ 6 Werte nicht überschreiten." Also müssen wir nie mehr als 10 ^ 6 Zahlen zusammenzählen? Meinen Sie, die Summe der Eingaben würde 10 ^ 6 nicht überschreiten?
Mellamokb
7
Spoiler: 1) Der Greedy-Algorithmus (subtrahiert die größte Fibonacci-Zahl, bis die Eingabe Null ist) liefert optimale Lösungen. 2) Für eine optimale Lösung muss eine Fibonacci-Zahl nicht zweimal verwendet werden (was aus 1 folgt). 3) Eine optimale Lösung für N <= 1000000 enthält nicht mehr als 14 Terme.
Joey Adams
6
@Joey: Im Allgemeinen zerlegt der Greedy-Algorithmus positive Ganzzahlen in Summen von unterschiedlichen Fibonacci-Zahlen, so dass aufeinanderfolgende Fibonacci-Zahlen nicht verwendet werden (dies wird als Satz von Zeckendorf bezeichnet).
Nabb
1
Spoiler 4: 29 Terme der Fibonacci-Sequenz ab 0 1 reichen aus.
Peter Taylor
@Nabb: Danke für die Erklärung des mathematischen Teils.
Quixotic

Antworten:

16

Motorola 68000-Assembly - 34 Byte

(GNU-Assembler-Syntax)

| short min_fib_partition(long N asm("%d2"), long *out asm("%a0"))
min_fib_partition:
    | Generate Fibonacci numbers on the stack (-1, 1, 0, 1, 1, 2, 3, ..., 1134903170).
    moveq #-1, %d0          | A = -1
    moveq #1, %d1           | B = 1
generate_loop:
    move.l %d0, -(%sp)      | Push A to the stack.
    exg.l %d0, %d1          | A' = B
    add.l %d0, %d1          | B' = A + B
    bvc.s generate_loop     | Stop when signed long overflows.

    | Go back up the stack, partitioning N using the greedy algorithm.
    moveq #0, %d0           | Initialize return value (number of terms).
subtract_loop:
    move.l (%sp)+, %d1      | Pop a Fibonacci number F off the stack.
    cmp.l %d1, %d2          | If N < F, continue to smaller Fibonacci number.
    blt.s subtract_loop
    addq.w #1, %d0          | Increment the term count.
    move.l %d1, (%a0)+      | Append F to the output array.
    sub.l %d1, %d2          | N -= F
    bne.s subtract_loop     | Continue if N has not yet reached zero.

    | Clear the stack by searching for that -1.
clear_stack_loop:
    tst.l (%sp)+
    bge clear_stack_loop

done:
    rts

36 → 34: Der Fibonacci-Generator wurde nicht durch Zählen, sondern durch Überlauf gestoppt und das 0Gehäuse so repariert, dass es [0]stattdessen ausgibt []. Allerdings Nstürzt das Übergeben eines Negativs jetzt ab.

Der Kommentar oben ist der C-Prototyp dieser Funktion und verwendet eine Spracherweiterung , um zu identifizieren, welche Parameter wohin gehen (standardmäßig werden sie auf dem Stapel abgelegt).

Mein TI-89 mit seinem 10-MHz-Prozessor benötigt 5 Minuten, um diese Funktion auf 1 - 1.000.000 auszuführen.

Obwohl der Maschinencode (derzeit) weniger Bytes enthält als die GolfScript-Lösung, wäre es wahrscheinlich unfair, dies als kürzeste Lösung zu akzeptieren, weil:

  • Maschinencode wird normalerweise nicht als "Quellcode" gezählt. Im Gegensatz zum Quellcode weist der Maschinencode normalerweise eine hohe Symbolkomplexität auf und ist, was noch wichtiger ist, nicht druckbar. Siehe " Sollten ausführbare Binärdateien als sinnvolle Lösung für Code-Golf angesehen werden? ".
  • Diese Lösung verwendet nur eine einzige Zahl als Eingabe und nicht mehrere Eingaben.
  • Diese Lösung ist eine Funktion, kein Programm.

Wenn Sie einen TI-89/92 / V200 haben, können Sie das vollständige Projekt hier herunterladen (veraltet):

https://rapidshare.com/files/154945328/minfib.zip

Viel Glück beim Überreden von RapidShare, Ihnen die eigentliche Datei zu geben. Kennt jemand einen guten Host für so große Dateien? 8940 ist eine Menge Bytes.

Joey Adams
quelle
Sie können der Liste einen vierten Punkt hinzufügen: Die Lösung gibt die Ausgabe nicht im richtigen Format aus: P Ich verwende nur 7 Zeichen für Zeichenfolgenliterale. Übrigens, geben Sie die Liste [0] für den Eingang 0 zurück? Es scheint mir, dass Sie die leere Liste zurückgeben. Es ist ein irritierender Sonderfall.
Peter Taylor
@ Peter Taylor: Du hast recht, das habe ich verpasst. Ich habe Begriffe und Begriffszählungen durcheinander gebracht. Ich werde bald einen Fix posten.
Joey Adams
5

Javascript (142)

Verarbeitet jeweils nur eine Eingabe. Weil mehrzeilige Eingabe für JavaScript unbrauchbar ist.

k=n=prompt(f=[a=b=1])|0;while((b=a+(a=b))<n)f.push(b);for(i=f.length,g=[];i--;)if(f[i]<=k)g.push(f[i]),k-=f[i];alert(n+': '+(n?g.join('+'):0))

http://jsfiddle.net/EqMXQ/

mellamokb
quelle
5

C 244 Zeichen

#define P printf
int f[30];int main(){f[28]=f[29]=1;int i=28;for(;i>0;--i)f[i-1]=f[i+1]+f[i];int x;while(scanf("%i",&x)!=-1){P(x?"%i: ":"0: 0\n",x);if(x>0){int i=0,a=0;while(x>0){while(f[i]>x)++i;if(a++)P("+");P("%i",f[i]);x-=f[i];}P("\n");}}}

Mit Leerzeichen:

#define P printf
int f[30];
int main(){
    f[28] = f[29] = 1;
    int i = 28;
    for(; i > 0; --i) f[i-1] = f[i+1] + f[i];
    int x;
    while(scanf("%i",&x) != -1) {
        P(x ? "%i: " : "0: 0\n",x);
        if(x > 0) {
            int i = 0, a = 0;
            while(x > 0) {
                while(f[i] > x) ++i;
                if(a++) P("+");
                P("%i",f[i]);
                x -= f[i];
            }
            P("\n");
        }
    }
}

Dieses Programm liest Zahlen aus der Standardeingabe und schreibt sie in die Standardausgabe.

ughoavgfhw
quelle
5

Golfscript, 43 Zeichen

~]{:|': '[{0 1{|>!}{.@+}/;|1$-:|}do]'+'*n}%

Ich denke, dass dies mit mehr Aufwand um 3 bis 5 Zeichen reduziert werden kann. ZB fühlt sich die Entfaltung, um dann das Array wegzuwerfen, verschwenderisch an.

Peter Taylor
quelle
3

F # - 282 252 241 Zeichen

let mutable d=int(stdin.ReadLine())
let q=d
let rec f x=if x<2 then 1 else f(x-2)+f(x-1)
let s x=
 d<-d-x
 x
printf"%d: %s"q (Core.string.Join("+",[for i in List.filter(fun x->x<d)[for i in 28..-1..0->f i]do if d-i>=0 then yield s i]))
nharren
quelle
3

Python - 183 Zeichen

Der Großteil des Codes verarbeitet mehrere Eingaben :(

f=lambda a,b,n:b>n and a or f(b,a+b,n)
g=lambda n:n>0and"%d+%s"%(f(0,1,n),g(n-f(0,1,n)))or""
try:
 while 1:
  n=input()
  print "%d: %s"%(n,n<1and"0"or g(n).strip("+"))
except:0
st0le
quelle
Können Sie das n=input()am Ende der vorherigen Zeile setzen?
mbomb007
Das nehme ich an. : \
st0le
Sie können einen Charakter auch speichern, indem Sie das Leerzeichen nachprint
mbomb007
2

Mathematica 88

n = RandomInteger[10000, 10];

Print[k=#,For[i=99;l={},k>0,If[#<=k,k-=#;l~AppendTo~#]&@Fibonacci@i--];":"l~Row~"+"]&/@n

Ausgabebeispiel

3999: 2584+987+377+34+13+3+1
9226: 6765+1597+610+233+21
7225: 6765+377+55+21+5+2
9641: 6765+2584+233+55+3+1
6306: 4181+1597+377+144+5+2
4507: 4181+233+89+3+1
8848: 6765+1597+377+89+13+5+2
6263: 4181+1597+377+89+13+5+1
2034: 1597+377+55+5
6937: 6765+144+21+5+2
ybeltukov
quelle
2

EXCEL: 89 Zeichen im eindeutigen Code:

Bildbeschreibung hier eingeben

user14011
quelle
1

Scala - 353 Zeichen (100 Zeichen für die Verarbeitung mehrerer Eingaben)

def h(m:Int){lazy val f={def g(a:Int,b:Int):Stream[Int]=a #:: g(b,a+b);g(0,1);};if(m==0)println(m+": "+m)else{var s=0;var t= f.takeWhile(_ <= m);var w="";while(s!= m){s+=t.last;w+=t.last+"+";t=t.takeWhile(_<=m-s);};println(m+": "+w.take(w.length-1))}}
Iterator.continually(Console.readLine).takeWhile(_ != "").foreach(line => h(Integer.parseInt(line)))
Lalith
quelle
Iterator.continually(Console.readLine).takeWhile(_ != "").foreach(line => h(Integer.parseInt(line)))könnte io.Source.stdin.getLines.foreach(l=>h(Integer.parseInt(l)))auf 40 Zeichen gekürzt werden .
Gareth
1

Python 3 (170 Zeichen)

while 1:
 s=input()
 if not s:break
 s=n=int(s);f=[1];t=[]
 while f[-1]<n:f+=[sum(f[-2:])]
 for i in f[::-1]:
  if s>=i:s-=i;t+=[i]
 print(n,'=','+'.join(map(str,t))or 0)

Mehrzeilige Eingabe, in Leerzeile anhalten

AMK
quelle
1

C 151 Zeichen

main() {int i=1,n,f[30]={1,1};for(;i++<30;)f[i]=f[i-1]+f[i-2];while(scanf("%d",&n))for(i=30;;--i)if(f[i]<=n){printf("%d\n",f[i]);if(!(n-=f[i]))break;}}

lesbare Version:

main() {
    int i=1,n,f[30]={1,1};
    for(;i++<30;)f[i]=f[i-1]+f[i-2];
    while(scanf("%d",&n))
        for(i=30;;--i)
            if(f[i]<=n) {
                printf("%d\n",f[i]);
                if (!(n-=f[i])) break;
            }
}
vmrob
quelle
1

R 170

x=scan();Filter(function(i)cat(unlist(Map(function(d)if(i>=d&&i){i<<-i-d;d},rev(lapply(Reduce(function(f,x)c(f[2],sum(f)),1:94,c(0,1),F,T),head,n=1)))),sep='+',fill=T),x)

Verarbeitet mehrere Eingaben und übergibt das Ergebnis an STDOUT

> x=scan();Filter(function(i)cat(unlist(Map(function(d)if(i>=d&&i){i<<-i-d;d},rev(lapply(Reduce(function(f,x)c(f[2],sum(f)),1:94,c(0,1),F,T),head,n=1)))),sep='+',fill=T),x)
1: 100
2: 200
3: 300
4: 
Read 3 items
89+8+3
144+55+1
233+55+8+3+1
numeric(0)
>
MickyT
quelle
1

R (460 Zeichen)

Eine andere Version mit R.
Lesen aus der Datei "Eingabe", Ausgabe in die Datei "Ausgabe"

d=as.list(as.integer(scan("input","",sep="\n")));n=36;f=rep(1,n);for(i in 3:n){f[i]=f[i-2]+f[i-1]};d2=lapply(d,function(x){a=vector("integer");i=1;while(x>0){id=which(f>=x)[1];if(x==f[id]){x=x-f[id];a[i]=f[id]}else{x=x-f[id-1];a[i]=f[id-1]}i=i+1}a});d=mapply(c,d,d2,SIMPLIFY=0);for(i in 1:length(d)){t=d[[i]];l=length(t);if(l==1){d[[i]]=paste(t[1],t[1],sep=": ")}else{d[[i]]=paste(t[1],": ",paste(t[2:l],collapse="+"),sep="")}}lapply(d,write,"output",append=1)

Beispiel "Eingabe"

0
47
3788
1646
25347
677
343
3434

Beispiel "Ausgabe"

0: 0
47: 34+13
3788: 2584+987+144+55+13+5
1646: 1597+34+13+2
25347: 17711+6765+610+233+21+5+2
677: 610+55+8+3+1
343: 233+89+21
3434: 2584+610+233+5+2

Mehr lesbare Version:

dt <- as.list(as.integer(scan(file = "input", what = "", sep = "\n")))
n <- 36
fib <- rep(1, n)
for(i in 3:n){fib[i] <- fib[i-2] + fib[i-1]}
dt2 <- lapply(dt, function(x){answ <- vector(mode = "integer")
                               i <- 1
                               while(x > 0){
                                   idx <- which(fib>=x)[1]
                                   if(x == fib[idx]){
                                       x <- x - fib[idx]
                                       answ[i] <- fib[idx]
                                   } 
                                   else {
                                       x <- x - fib[idx-1]
                                       answ[i] <- fib[idx-1]
                                   }
                                   i <- i + 1
                               }
                               answ})
dt <- mapply(FUN = c, dt, dt2, SIMPLIFY = FALSE)
for(i in 1:length(dt)){
    t1 <- dt[[i]]
    t1.len <- length(t1)
    if(t1.len == 1){
        dt[[i]] <- paste(t1[1], t1[1], sep=": ")
    } else {
        dt[[i]] <- paste(t1[1], ": ", paste(t1[2:t1.len], collapse = "+"), sep="")
    }
}
lapply(dt, write, "output", append=TRUE)
AndriusZ
quelle
0

D (196 Zeichen)

Laufen Sie mit rdmd --eval=…. Dies verbirgt bequem die Kesselplatte von import x, y, z;und void main() {…}:

int f(int i){return i-->1?f(i--)+f(i):i+2;}int n;foreach(x;std.stdio.stdin.byLine.map!(to!int))writeln(x,": ",x?n=x,reduce!((r,i)=>f(i)<=n?n-=f(i),r~="+"~f(i).text:r)("",29.iota.retro)[1..$]:"0")
mleise
quelle
0

Java verwenden

package org.mindcraft;

import java.util.Scanner;

public class Fibbo {
    public static void main(String[] args) {
    String number = null;
    int tmp, sum;
    int i = 1, j = 1;
    Scanner in = new Scanner(System.in);
    number = in.nextLine();
    String[] arr = number.split(" ");
    for (int it = 0; it < arr.length; it++) {
        tmp = Integer.parseInt(arr[it]);
        String value = tmp+" : ";
        while (tmp > 0) {
            i = 1;
            j = 1;
            for (int k = 0; k < 10000; k++) {
                sum = i + j;
                if (sum > tmp) {
                    //if (value == null) {
                    char ch=value.charAt(value.length()-2);
                    if(ch==':')
                    {
                        value = value+" "+ j + "";
                    } else {
                        value = value + " + " + j;
                    }

                    tmp = tmp - j;
                    break;
                }
                i = j;
                j = sum;
            }
        }
        System.out.println(value);
    }
}
}
Manoj Gupta
quelle
Dies ist Code-Golf, also spielen Sie Ihre Antwort unbedingt Golf.
KSFT
1
Willkommen bei PPCG! Wie KSFT sagte, ist dies eine Code-Golf- Herausforderung. Bitte geben Sie sich Mühe, diese Frage in möglichst wenigen Byte Code zu beantworten. Zumindest können Sie unnötige Leerzeichen entfernen und Namen von Klassen / Methoden / Variablen mit einem Buchstaben verwenden. Bitte geben Sie danach auch die Anzahl der Bytes in Ihre Antwort ein.
Martin Ender