Thử thách tối thiểu của Wikipedia!


19

Thử thách

Trong tác vụ này, bạn sẽ được cấp một số nguyên N (nhỏ hơn 10 6 ), tìm cách tối thiểu mà bạn có thể tính tổng bằng N chỉ bằng các số Fibonacci - phân vùng này được gọi là biểu diễn Zeckendorf .

Bạn có thể sử dụng bất kỳ số Fibonacci nào nhiều lần và nếu có nhiều hơn một đầu ra đại diện bất kỳ.

Ví dụ: nếu đầu vào là 67 thì một đầu ra có thể có thể sử dụng các số Fibonacci 1,3,8,55 , đây cũng là số lượng tối thiểu của các số Fibonacci có thể được sử dụng để lấy tổng 67 .

Đầu vào N được đưa ra trên một dòng duy nhất, đầu vào được kết thúc bằng EOF.

Ví dụ

Đưa ra trong định dạng 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

Những ràng buộc

  • Số lượng đầu vào sẽ không vượt quá 10 6 giá trị.
  • Chương trình của bạn không nên chạy quá 5 giây cho tất cả các đầu vào.
  • Bạn có thể sử dụng bất kỳ ngôn ngữ nào bạn chọn.
  • Giải pháp ngắn nhất sẽ thắng!

"Bạn có thể có bất kỳ số Fibonacci nào ..." eh? "Số lượng đầu vào sẽ không vượt quá 10 ^ 6 giá trị." Vì vậy, chúng ta sẽ không bao giờ cần phải thêm nhiều hơn 10 ^ 6 số với nhau? Bạn có nghĩa là tổng số đầu vào sẽ không vượt quá 10 ^ 6?
mellamokb

7
Spoiler: 1) Thuật toán tham lam (trừ số Fibonacci lớn nhất cho đến khi đầu vào bằng 0) tạo ra các giải pháp tối ưu. 2) Một giải pháp tối ưu không cần sử dụng số Fibonacci hai lần (theo sau từ 1). 3) Một giải pháp tối ưu, với N <= 1000000, sẽ có không quá 14 điều khoản.
Joey Adams

6
@Joey: Nói chung, thuật toán tham lam phân rã các số nguyên dương thành tổng của các số Fibonacci riêng biệt sao cho các số Fibonacci liên tiếp không được sử dụng (đây được gọi là định lý của Zeckendorf).
Nabb

1
Spoiler 4: 29 điều khoản của chuỗi Fibonacci bắt đầu từ 0 1 là đủ.
Peter Taylor

@Nabb: Cảm ơn bạn đã giải thích phần toán học.
Quixotic

Câu trả lời:


16

Lắp ráp Motorola 68000 - 34 byte

(Cú pháp trình biên dịch 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

36 → 34: Đã tạo bộ tạo Fibonacci dừng trên tràn thay vì đếm và sửa 0trường hợp để nó xuất ra [0]chứ không phải []. Tuy nhiên, vượt qua một Ntai nạn tiêu cực bây giờ.

Nhận xét ở trên cùng là nguyên mẫu C của chức năng này, sử dụng phần mở rộng ngôn ngữ để xác định tham số nào đi đâu (theo mặc định, chúng đi trên ngăn xếp).

TI-89 của tôi , với bộ xử lý 10 MHz, mất 5 phút để chạy chức năng này trên 1 - 1.000.000.

Mặc dù mã máy (hiện tại) ít byte hơn giải pháp GolfScript, nhưng có lẽ sẽ không công bằng khi chấp nhận đây là giải pháp ngắn nhất vì:

Nếu bạn có TI-89/92 / V200, bạn có thể tải xuống toàn bộ dự án tại đây (lỗi thời):

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

Chúc may mắn dỗ RapidShare để cung cấp cho bạn các tập tin thực tế. Có ai biết một máy chủ tốt cho các tập tin lớn này? 8940 là rất nhiều byte.


Bạn có thể thêm một điểm thứ tư vào danh sách: giải pháp không cung cấp đầu ra ở định dạng đúng: P Tôi chỉ sử dụng 7 ký tự trên chuỗi ký tự. BTW Bạn có trả về danh sách [0] cho đầu vào 0 không? Dường như với tôi rằng bạn trả lại danh sách trống. Đó là một trường hợp đặc biệt khó chịu.
Peter Taylor

@Peter Taylor: Bạn nói đúng, tôi đã bỏ lỡ điều đó. Tôi có các điều khoản và số lượng hạn trộn lẫn. Tôi sẽ sớm sửa lỗi.
Joey Adams

5

Javascript (142)

Chỉ xử lý đầu vào duy nhất tại một thời điểm. Bởi vì đầu vào nhiều dòng là vô dụng đối với 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 ký tự

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

Với khoảng trắng:

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

Chương trình này sẽ đọc các số trong đầu vào tiêu chuẩn và ghi vào đầu ra tiêu chuẩn.


5

Golfscript, 43 ký tự

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

Tôi nghĩ rằng điều này có thể có thể giảm từ 3 đến 5 ký tự với nhiều nỗ lực hơn. Ví dụ, việc mở ra để sau đó vứt bỏ mảng cảm thấy lãng phí.


3

F # - 282 252 241 ký tự

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

Phần lớn mã đang xử lý nhiều đầu vào :(

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

Bạn có thể đặt n=input()ở cuối dòng trước không?
mbomb007

Tôi cho là như vậy. : \
st0le

Bạn cũng có thể lưu một ký tự bằng cách xóa khoảng print
trắng

2

Toán học 88

n = RandomInteger[10000, 10];

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

Ví dụ về đầu ra

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 ký tự (100 ký tự để xử lý nhiều đầu vào)

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)))có thể rút ngắn để io.Source.stdin.getLines.foreach(l=>h(Integer.parseInt(l)))lưu các ký tự 40-ish.
Gareth

1

Python 3 (170 ký tự)

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)

Đầu vào đa dòng, dừng trên dòng trống


1

C, 151 ký tự

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

phiên bản có thể đọc được:

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)

Xử lý nhiều đầu vào và kết quả là 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 ký tự)

Một phiên bản khác sử dụng R.
Đọc từ tệp "đầu vào", xuất ra tệp "đầu ra"

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)

ví dụ "đầu vào"

0
47
3788
1646
25347
677
343
3434

ví dụ "đầu ra"

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

Phiên bản dễ đọc hơn:

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 ký tự)

Chạy với rdmd --eval=…. Điều này thuận tiện che giấu các nồi hơi của import x, y, z;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

Sử dụng 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);
    }
}
}

Đây là mã golf, vì vậy hãy chắc chắn để đánh golf câu trả lời của bạn.
KSFT

1
Chào mừng đến với PPCG! Như KSFT đã nói, đây là một thử thách chơi gôn . Vui lòng cho thấy một số nỗ lực trong việc trả lời câu hỏi này trong càng ít byte mã càng tốt. Ít nhất, bạn có thể loại bỏ khoảng trắng không cần thiết và sử dụng tên lớp / phương thức / tên biến đơn. Sau khi làm điều này, xin vui lòng bao gồm số byte trong câu trả lời của bạn.
Martin Ender
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.