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!

"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.


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/


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.


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.


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]))

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

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


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)))

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


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

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)
>

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)

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")

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

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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.