Tantangan fibonacci minimum!


19

Tantangan

Dalam tugas ini Anda akan diberikan integer N (kurang dari 10 6 ), temukan cara minimum di mana Anda bisa menjumlahkan ke N hanya menggunakan angka Fibonacci - partisi ini disebut representasi Zeckendorf .

Anda bisa menggunakan angka Fibonacci lebih dari sekali dan jika ada lebih dari satu hasil representasi.

Misalnya jika inputnya adalah 67 maka satu kemungkinan output bisa menggunakan angka Fibonacci 1,3,8,55 yang juga merupakan angka minimum dari angka Fibonacci yang bisa digunakan untuk mendapatkan jumlah 67 .

Input N diberikan pada satu baris, input diakhiri oleh EOF.

Contohnya

Diberikan dalam format 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

Kendala

  • Jumlah input tidak akan melebihi nilai 10 6 .
  • Program Anda tidak boleh berjalan lebih dari 5 detik untuk semua input.
  • Anda dapat menggunakan bahasa pilihan Anda.
  • Solusi terpendek menang!

"Kamu bisa nomor Fibonacci ..." eh? "Jumlah input tidak akan melebihi nilai 10 ^ 6." Jadi kita tidak perlu menambahkan lebih dari 10 ^ 6 angka bersamaan? Apakah maksud Anda jumlah input tidak akan melebihi 10 ^ 6?
mellamokb

7
Spoiler: 1) Algoritma serakah (kurangi angka Fibonacci terbesar hingga input nol) menghasilkan solusi optimal. 2) Solusi optimal tidak perlu menggunakan angka Fibonacci dua kali (yang mengikuti dari 1). 3) Solusi optimal, untuk N <= 1000000, tidak akan memiliki lebih dari 14 istilah.
Joey Adams

6
@ Joey: Lebih umum, algoritma serakah menguraikan bilangan bulat positif menjadi jumlah angka Fibonacci yang berbeda sehingga angka Fibonacci berturut-turut tidak digunakan (ini disebut teorema Zeckendorf).
Nabb

1
Spoiler 4: 29 syarat dari urutan Fibonacci mulai dari 0 1 sudah cukup.
Peter Taylor

@Nabb: Terima kasih telah menjelaskan bagian matematika.
Quixotic

Jawaban:


16

Motorola 68000 assembly - 34 byte

(Sintaks assembler GNU)

| 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

34 → 34: Membuat generator Fibonacci berhenti pada overflow bukan dengan menghitung, dan memperbaiki 0case sehingga menghasilkan [0]bukan []. Namun, melewati Ntabrakan negatif sekarang.

Komentar di atas adalah prototipe C dari fungsi ini, menggunakan ekstensi bahasa untuk mengidentifikasi parameter apa yang pergi ke mana (secara default, mereka pergi di stack).

Saya TI-89 , dengan prosesor 10MHz nya, membutuhkan waktu 5 menit untuk menjalankan fungsi ini pada 1 - 1.000.000.

Meskipun kode mesin (saat ini) lebih sedikit byte daripada solusi GolfScript, mungkin tidak adil untuk menerima ini sebagai solusi terpendek karena:

Jika Anda memiliki TI-89/92 / V200, Anda dapat mengunduh proyek selengkapnya di sini (kedaluwarsa):

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

Semoga berhasil membujuk RapidShare untuk memberi Anda file yang sebenarnya. Adakah yang tahu host yang bagus untuk file sebesar ini? 8940 adalah banyak sekali byte.


Anda bisa menambahkan poin keempat ke daftar: solusinya tidak memberikan output dalam format yang benar: P Saya menggunakan 7 karakter pada string literal saja. BTW Apakah Anda mengembalikan daftar [0] untuk input 0? Tampak bagi saya bahwa Anda mengembalikan daftar kosong. Ini kasus khusus yang menjengkelkan.
Peter Taylor

@ Peter Taylor: Anda benar, saya melewatkan itu. Saya mendapatkan persyaratan dan jumlah persyaratan yang beragam. Saya akan segera memposting perbaikan.
Joey Adams

5

Javascript (142)

Hanya menangani input tunggal pada satu waktu. Karena input multi-baris tidak berguna untuk JavaScript.

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 karakter

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

Dengan spasi putih:

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

Program ini akan membaca angka dari input standar dan menulis ke output standar.


5

Golfscript, 43 karakter

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

Saya pikir ini mungkin dapat dikurangi dengan 3 hingga 5 karakter dengan lebih banyak usaha. Misalnya membuka untuk kemudian membuang array terasa sia-sia.


3

F # - 282 252 241 karakter

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 Chars

Mayoritas kode menangani banyak input :(

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

Bisakah Anda meletakkannya n=input()di akhir baris sebelumnya?
mbomb007

Saya rasa begitu. : \
st0le

Anda juga dapat menyimpan karakter dengan menghapus spasi setelahprint
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

Contoh output

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 karakter (100 karakter untuk menangani beberapa input)

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)))dapat disingkat menjadi io.Source.stdin.getLines.foreach(l=>h(Integer.parseInt(l)))untuk menyimpan 40-ish karakter.
Gareth

1

Python 3 (170 karakter)

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)

Input multiline, berhenti di jalur kosong


1

C, 151 karakter

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

versi yang dapat dibaca:

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)

Menangani banyak input dan memberikan hasilnya ke 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 karakter)

Versi lain menggunakan R.
Membaca dari file "input", output ke file "output"

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)

"masukan" contoh

0
47
3788
1646
25347
677
343
3434

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

Versi yang lebih mudah dibaca:

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

Jalankan dengan rdmd --eval=…. Ini dengan nyaman menyembunyikan boilerplate import x, y, z;dan 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

Menggunakan Java

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

Ini adalah kode golf, jadi pastikan untuk mengirim jawaban Anda ke golf.
KSFT

1
Selamat datang di PPCG! Seperti yang dikatakan KSFT, ini adalah tantangan kode-golf . Tolong tunjukkan usaha dalam menjawab pertanyaan ini dalam beberapa byte kode mungkin. Paling tidak, Anda dapat menghapus spasi yang tidak perlu dan menggunakan kelas huruf tunggal / metode / nama variabel. Setelah melakukan ini, harap sertakan juga jumlah byte dalam jawaban Anda.
Martin Ender
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.