ความท้าทายของฟีโบนักชีขั้นต่ำ!


19

ท้าทาย

ในงานนี้คุณจะได้รับจำนวนเต็ม N (น้อยกว่า 10 6 ) หาทางขั้นต่ำในที่ที่คุณสามารถที่จะสรุป N โดยใช้เพียงตัวเลข Fibonacci - พาร์ทิชันนี้จะเรียกว่าเป็นตัวแทน Zeckendorf

คุณสามารถใช้หมายเลข Fibonacci ใด ๆ มากกว่าหนึ่งครั้งและหากมีการแสดงผลมากกว่าหนึ่งรายการ

ตัวอย่างเช่นถ้าใส่เป็น67แล้วหนึ่งเอาท์พุทที่เป็นไปได้อาจจะใช้ตัวเลข Fibonacci 1,3,8,55ซึ่งยังเป็นจำนวนขั้นต่ำของตัวเลข Fibonacci ที่สามารถนำมาใช้เพื่อให้ได้ผลรวม67

อินพุต N ถูกกำหนดบนบรรทัดเดียวอินพุตถูกยกเลิกโดย EOF

ตัวอย่าง

ได้รับในรูปแบบ 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

ข้อ จำกัด

  • จำนวนอินพุตไม่เกิน 10 6ค่า
  • โปรแกรมของคุณไม่ควรรันเกิน 5 วินาทีสำหรับอินพุตทั้งหมด
  • คุณสามารถใช้ภาษาที่คุณเลือกได้
  • ทางออกที่สั้นที่สุดชนะ!

"คุณสามารถหมายเลขฟีโบนักชี ... " ใช่มั้ย "จำนวนอินพุตไม่เกิน 10 ^ 6 ค่า" ดังนั้นเราไม่จำเป็นต้องเพิ่มตัวเลขมากกว่า 10 ^ 6 เข้าด้วยกันใช่ไหม คุณหมายถึงผลรวมของอินพุตจะไม่เกิน 10 ^ 6 หรือไม่?
mellamokb

7
สปอยเลอร์: 1) อัลกอริทึมโลภ (ลบหมายเลขฟีโบนักชีที่ใหญ่ที่สุดจนกระทั่งอินพุตเป็นศูนย์) สร้างโซลูชันที่ดีที่สุด 2) ทางออกที่ดีที่สุดไม่จำเป็นต้องใช้หมายเลขฟีโบนักชีสองครั้ง (ซึ่งต่อจาก 1) 3) ทางออกที่ดีที่สุดสำหรับ N <= 1000000 จะมีไม่เกิน 14 คำ
Joey Adams

6
@ โจอี้: โดยทั่วไปแล้วขั้นตอนวิธีโลภจะสลายจำนวนเต็มบวกเป็นผลบวกของจำนวนฟีโบนักชีที่แตกต่างกันซึ่งไม่ได้ใช้หมายเลขฟีโบนักชีต่อเนื่องกัน (นี่เรียกว่าทฤษฎีบทของ Zeckendorf)
Nabb

1
สปอยเลอร์ 4: 29 เงื่อนไขของลำดับฟีโบนักชีเริ่มต้นที่ 0 1 นั้นเพียงพอแล้ว
Peter Taylor

@Nabb: ขอบคุณที่อธิบายส่วนคณิตศาสตร์
Quixotic

คำตอบ:


16

ชุดประกอบ Motorola 68000 - 34 ไบต์

(ไวยากรณ์แอสเซมเบลอร์ 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: Made Fibonacci หยุดกำเนิดในล้นมากกว่าโดยการนับและการแก้ไข0กรณีดังนั้นมันจะออกผลลัพธ์มากกว่า[0] []อย่างไรก็ตามการผ่านNล้มเหลวเชิงลบในขณะนี้

ความคิดเห็นที่ด้านบนคือต้นแบบ C ของฟังก์ชั่นนี้โดยใช้ส่วนขยายภาษาเพื่อระบุพารามิเตอร์ที่ไป (โดยค่าเริ่มต้นพวกเขาไปที่สแต็ค)

TI-89ของฉันพร้อมโปรเซสเซอร์ 10MHz ใช้เวลา 5 นาทีในการเรียกใช้ฟังก์ชั่นนี้ใน 1 - 1,000,000

แม้ว่ารหัสเครื่อง (ในปัจจุบัน) จะน้อยกว่าไบต์โซลูชัน GolfScript แต่ก็อาจไม่ยุติธรรมที่จะยอมรับว่านี่เป็นวิธีแก้ปัญหาที่สั้นที่สุดเพราะ:

หากคุณมี TI-89/92 / V200 คุณสามารถดาวน์โหลดโครงการทั้งหมดได้ที่นี่ (ล้าสมัย):

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

ขอให้โชคดีในการเกลี้ยกล่อม RapidShare เพื่อให้ไฟล์จริงแก่คุณ ไม่มีใครรู้ว่าโฮสต์ที่ดีสำหรับไฟล์ขนาดใหญ่นี้? 8940 มีจำนวนไบต์ที่แย่มาก


คุณสามารถเพิ่มจุดที่สี่ในรายการ: การแก้ปัญหาไม่ได้ให้ผลลัพธ์ในรูปแบบที่ถูกต้อง: P ฉันใช้ 7 ตัวอักษรในสตริงตัวอักษรเพียงอย่างเดียว BTW คุณส่งคืนรายการ [0] สำหรับอินพุต 0 หรือไม่ ดูเหมือนว่าคุณจะส่งคืนรายการว่างเปล่า มันเป็นกรณีพิเศษที่น่ารำคาญ
ปีเตอร์เทย์เลอร์

@ Peter เทย์เลอร์: ถูกต้องฉันพลาดไป ฉันได้รับการนับจำนวนคำและเทอมรวมกัน ฉันจะโพสต์การแก้ไขในไม่ช้า
Joey Adams

5

Javascript (142)

จัดการอินพุตครั้งละหนึ่งรายการเท่านั้น เนื่องจากอินพุตหลายบรรทัดไม่มีประโยชน์สำหรับ 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 ตัวอักษร

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

ด้วยช่องว่าง:

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

โปรแกรมนี้จะอ่านตัวเลขจากอินพุตมาตรฐานและเขียนไปยังเอาต์พุตมาตรฐาน


5

Golfscript, 43 ตัวอักษร

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

ฉันคิดว่าสิ่งนี้อาจลดลงได้ 3 ถึง 5 ตัวอักษรด้วยความพยายามมากขึ้น เช่นแฉที่จะโยนทิ้งไปอาเรย์รู้สึกสิ้นเปลือง


3

F # - 282 252 241 ตัวอักษร

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

ส่วนใหญ่ของรหัสคือการจัดการหลายอินพุต :(

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

คุณสามารถใส่n=input()ท้ายบรรทัดก่อนหน้าได้หรือไม่?
mbomb007

ผมว่าอย่างนั้น. : \
st0le

นอกจากนี้คุณยังสามารถบันทึกตัวละครโดยการลบช่องว่างหลังจากprint
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

ตัวอย่างผลลัพธ์

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 ตัวอักษร (100 ตัวอักษรสำหรับจัดการหลายอินพุต)

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)))สามารถย่อให้io.Source.stdin.getLines.foreach(l=>h(Integer.parseInt(l)))เหลือขนาดอักขระได้ 40 ตัว
Gareth

1

Python 3 (170 ตัวอักษร)

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)

อินพุตหลายบรรทัดหยุดที่บรรทัดว่าง


1

C, 151 ตัวอักษร

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

รุ่นที่อ่านได้:

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)

จัดการอินพุตหลายอินพุตและ cat ให้ผลลัพธ์เป็น 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 ตัวอักษร)

รุ่นอื่นที่ใช้อาร์
อ่านจากไฟล์ "อินพุต" เอาต์พุตไปยังไฟล์ "เอาต์พุต"

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)

ตัวอย่าง "อินพุต"

0
47
3788
1646
25347
677
343
3434

ตัวอย่าง "เอาท์พุท"

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

รุ่นที่อ่านเพิ่มเติมได้:

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 ตัวอักษร)

rdmd --eval=…ทำงานด้วย สิ่งนี้จะซ่อนสิ่งที่ต้ม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

ใช้จาวา

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

นี่คือรหัสกอล์ฟดังนั้นอย่าลืมตีคำตอบของคุณ
KSFT

1
ยินดีต้อนรับสู่ PPCG! ดังที่ KSFT กล่าวว่านี่เป็นความท้าทายของนักกอล์ฟ โปรดแสดงความพยายามในการตอบคำถามนี้ด้วยรหัสน้อยที่สุดเท่าที่จะทำได้ อย่างน้อยที่สุดคุณสามารถลบช่องว่างที่ไม่จำเป็นออกและใช้ชื่อคลาส / เมธอด / ตัวแปร / ตัวอักษรเดียว หลังจากทำเช่นนี้โปรดระบุจำนวนไบต์ในคำตอบของคุณ
Martin Ender
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.