นับสี่เหลี่ยม


18

ท้าทาย

Origami (กระดาษพับ) เป็นรูปแบบศิลปะที่สร้างสรรค์ เท่าที่ฉันรู้ต้นแบบของ Origami ชอบกระดาษสี่เหลี่ยม มาเริ่มกันตั้งแต่ต้น - แปลงกระดาษสี่เหลี่ยมเป็นสี่เหลี่ยมจัตุรัส

ดังนั้นกระดาษถูกแบ่งออกเป็นสี่เหลี่ยม เราลบสี่เหลี่ยมที่ใหญ่ที่สุดซึ่งแบ่งขอบที่สั้นกว่าหนึ่งอันด้วยรูปร่างปัจจุบันทีละขั้นตอน (ดูภาพด้านล่าง) และถ้าส่วนที่เหลือหลังจากขั้นตอนเดียวน้อยกว่าหรือเท่ากับ0.001 * (area of the original paper)กระดาษจะไม่สามารถแบ่งออกได้อีก เป็นไปได้ว่าไม่มีอะไรเหลืออยู่ในที่สุด

งานของคุณคือการคำนวณจำนวนสี่เหลี่ยมที่ทำระหว่างกระบวนการ สี่เหลี่ยมในขั้นตอนสุดท้ายที่ทำให้กระดาษที่ไม่สามารถแบ่งออกได้จะถูกนับเป็นเอาท์พุท

ตัวอย่าง (กระดาษที่มี1.350ความกว้าง / สูง) เอาต์พุตคือ 10:

ตัวอย่างชิ้น

อินพุตและเอาต์พุต

การป้อนข้อมูล: ความกว้าง / ความสูงอัตราส่วนสำหรับกระดาษสี่เหลี่ยมทศนิยมหนึ่ง (หรือจำนวนเต็มโดยไม่ต้องจุด) จาก1.002การมีขั้นตอนน้อยที่สุด1.999 0.001นอกจากนี้คุณยังสามารถใช้รูปแบบที่เหมาะสมอื่น ๆ ที่อธิบายอัตราส่วน เพียงแค่พูดถึงมันในคำตอบของคุณ

เอาต์พุต: การนับสแควร์, หนึ่งจำนวนเต็ม

ตัวอย่าง I / O

รูปแบบการจับคู่ใช้เพื่อรักษาความเป็นระเบียบเรียบร้อยของหน้าเว็บในขณะที่รหัสของคุณไม่จำเป็นต้องรองรับการป้อนข้อมูลรายการหรือฟังก์ชั่นการทำแผนที่

1.002 => 251
1.003 => 223
1.004 => 189
1.005 => 161
1.006 => 140
1.007 => 124
1.008 => 111
1.009 => 100

รายการคำตอบทั้งหมด

ขอบคุณ @LuisMendo นี่คือกราฟคำตอบ

กราฟ

หมายเหตุ

  • นี่คือรหัสกอล์ฟที่สั้นที่สุดที่จะชนะ
  • เอาใจใส่กับช่องโหว่มาตรฐาน
  • เป็นอิสระในการตัดสินใจว่าจะจัดการกับอินพุทและเอาท์พุท แต่ควรปฏิบัติตามข้อ จำกัด มาตรฐาน

ยังไงซะ...

  • แสดงความคิดเห็นหากคุณมีอะไรที่ไม่ชัดเจนเกี่ยวกับความท้าทาย
  • ส่วนตัวผมขอแนะนำคำตอบของคุณมีคำอธิบายหากคุณใช้ภาษากอล์ฟ
  • ขอบคุณ @GregMartin อ่านคำตอบของเขาสำหรับคำอธิบายทางคณิตศาสตร์ที่ดีสำหรับความท้าทาย

รหัสตัวอย่าง

นี่คือรหัส C ++ ที่ไม่ได้บรรจุ:

#include <iostream>
#include <utility>

int f (double m)
{
    double n = 1, k = 0.001;
    int cnt = 0;
    k *= m;                       // the target minimum size
    while(m*n >= k)
    {
        m -= n;                   // extract a square
        if(n > m)
            std::swap(n, m);      // keep m > n
        ++ cnt;
    }
    return cnt;
}

int main()
{
    double p;
    std::cin >> p;
    std::cout << f(p);
    return 0;
}

การคำนวณทั้งหมดที่เกี่ยวข้องในรหัสตัวอย่างต้องการความถูกต้องของ 6 floatหลักทศนิยมซึ่งจะครอบคลุมใน


สามารถใช้ตัวเลขสองตัวที่สร้างอัตราส่วนเป็นอินพุตได้หรือไม่
Luis Mendo

@ LuisMendo ใช่ตามที่คุณต้องการ
Keyu Gan

2
ท้าทายมาก!
ข้อบกพร่อง

5
รายการคำตอบสร้างกราฟที่ดี
Luis Mendo

1
@KeyuGan แน่นอนไปข้างหน้า! แจ้งให้เราทราบหากคุณต้องการรุ่นที่มีรูปแบบอื่น
Luis Mendo

คำตอบ:


2

MATL , 19 ไบต์

`SZ}y-htG/p1e-3>}x@

[1, 1.009]การป้อนข้อมูลที่เป็นอาร์เรย์ด้วยตัวเลขสองการกำหนดอัตราส่วนเดิมเช่น (ไม่จำเป็นว่าจะต้องเรียงตัวเลขหรือหนึ่งในนั้นคือ 1)

ลองออนไลน์!

คำอธิบาย

`        % Do...while loop
  S      %   Sort array. Takes 1×2 array as input (implicit) the first time
  Z}     %   Split array into its 2 elements: first the minimum m, then the maximum M
  y      %   Duplicate m onto the top of the stack. The stack now contains m, M, m
  -      %   Subtract. The stack now contains m, M-m
  h      %   Concatenate into [m, M-m]. This is the remaining piece of paper
  t      %   Duplicate
  G/     %   Divide by input, element-wise
  p      %   Product of array. Gives ratio of current piece's area to initial area
  1e-3>  %   True if this ratio exceeds 1e-3. In that case the loop continues
}        % Finally (execute after last iteration, but still within the loop)
  x      %   Delete last piece of paper
  @      %   Push current loop counter. This is the result
         % End (implicit)
         % Display (implicit)

6

Haskell , 71 70 65 63 62 61 58 56 56 ไบต์

ขอบคุณ @xnor สำหรับการปรับปรุงที่แยบยล!

(n#m)e|e>n*m*1e3=0|n<m=m#n$e|d<-n-m=(d#m)e+1
n!m=n#m$n*m

ลองออนไลน์!


คิดว่าm==nท้ายที่สุดอาจเป็น1>0เพราะความเป็นไปได้ที่เหลืออยู่เพียงอย่างเดียว หรือบางทีกรณีอาจถูกจัดเรียงใหม่เพื่ออนุญาตให้ผูกที่นี่
xnor

ที่จริงแล้วกรณีความเท่าเทียมกันจำเป็นไหม? หากn>mมีการขยายไปถึงn>=mและการตรวจสอบครั้งแรกจะถูกเขียนe>m*n*1000ที่ควรให้1ความเท่าเทียมกัน
xnor

@xnor ความคิดที่ดีขอบคุณ!
ข้อบกพร่อง

1
ย้ายไปรอบ ๆ ยามสำหรับ 56:(n#m)e|e>n*m*1e3=0|n<m=m#n$e|d<-n-m=(d#m)e+1;n!m=n#m$n*m
xnor

ว้าวการใช้d<-n-mอย่างที่otherwiseเป็นระเบียบจริงๆ !!!
ข้อบกพร่อง

4

JavaScript (ES6), 59 58 ไบต์

f=(m,n=!(k=m/1e3,c=0))=>m*n<k?c:(c++,m-=n)<n?f(n,m):f(m,n)

ทดสอบ


4

Mathematica ไม่ใช่ผู้แข่งขัน (21 ไบต์)

คำตอบนี้ไม่ใช่การแข่งขันเพราะไม่ตอบคำถามจริงที่ถาม! แต่มันจะตอบคำถามที่แตกต่างและให้ข้อแก้ตัวเพื่อเน้นคณิตศาสตร์ที่น่าสนใจ

Tr@*ContinuedFraction

ฟังก์ชั่นสัญลักษณ์ที่ใช้จำนวนตรรกยะบวกเป็นอินพุต (ซึ่งตัวเศษและส่วนแสดงถึงมิติของกระดาษต้นฉบับ) และส่งคืนจำนวนเต็มบวก ตัวอย่างเช่นผลตอบแทนTr@*ContinuedFraction[1350/1000] 10( ContinuedFractionทำหน้าที่แตกต่างกันในจำนวนจุดลอยตัวเนื่องจากปัญหาความแม่นยำซึ่งเป็นสาเหตุที่จำเป็นต้องใช้จำนวนตรรกยะเป็นอินพุตในบริบทนี้)

การตีความขั้นตอนทางเรขาคณิตที่น่าสนใจที่อธิบายไว้ในปัญหา (การตัดสี่เหลี่ยมออกซ้ำ ๆ ) คือการใช้อัลกอริทึมแบบยุคลิดเพื่อหาตัวหารสามัญที่ยิ่งใหญ่ที่สุด! ลองพิจารณาตัวอย่างในคำถามด้วยอัตราส่วน1.35ซึ่งสามารถสร้างแบบจำลองโดยใช้กระดาษแผ่นหนึ่งที่มีขนาด (1350,1000) ทุกครั้งที่ตัดสี่เหลี่ยมจัตุรัสจำนวนที่น้อยกว่าจะถูกลบออกจากจำนวนที่มากขึ้น ดังนั้นรูปสี่เหลี่ยมผืนผ้าที่เกิดขึ้นในตัวอย่างนี้มีขนาด (350,1000), แล้ว (350,650), (350,300), แล้ว (50,300), (50,300) และ (50,200) และ (50,150) และ (50,100) และ (50,100) 50) และ (50,0) เมื่อเราเอาตารางสุดท้ายออกจากตัวมันเอง นี่คือวิธีที่อัลกอริทึมแบบยุคลิดทำงาน (โมดูโลความแตกต่างระหว่างการหารและการลบซ้ำ) และเราเห็นว่า 50 เป็น GCD ที่ 1350 และ 1,000

โดยทั่วไปแล้วในอัลกอริธึมแบบยุคลิดเราจะติดตามขนาดกลางเหล่านี้และละทิ้งจำนวนการลบ อย่างไรก็ตามเราสามารถบันทึกจำนวนครั้งที่เราลบจำนวนหนึ่งจากอีกจำนวนหนึ่งก่อนที่ความแตกต่างจะเล็กเกินไปและเราต้องสลับสิ่งที่เราลบออก วิธีการบันทึกนั้นเป็นเศษส่วนต่อเนื่องของจำนวนตรรกยะ (เศษส่วนต่อเนื่องของจำนวนอตรรกยะที่ไม่สิ้นสุดก็ยังยอดเยี่ยมเช่นกัน แต่ไม่เกี่ยวข้องกันที่นี่) ตัวอย่างเช่นในตัวอย่าง 1350/1000 เราตัด 1,000 1ครั้งแล้ว 350 2ครั้งจากนั้น 300 1ครั้งแล้ว 50 6ครั้ง; ดังนั้นจึงมีส่วนอย่างต่อเนื่องของ 1350/1000 {1,2,1,6}เป็น ในทางคณิตศาสตร์เราได้เขียน 1350/1000 ใหม่เป็น1+ 1 / ( 2+ 1 / ( 1+ 1 /6)) ซึ่งคุณสามารถตรวจสอบได้

ดังนั้นสำหรับปัญหานี้ถ้าคุณไม่หยุดเมื่อสแควร์สมีขนาดเล็กกว่าบาง threshhold แต่เพียงนับจำนวนสแควร์ทั้งหมดที่มีขอบเขตก่อนที่มันจะหยุดแล้วจำนวนสแควร์ทั้งหมดจะเท่ากับจำนวนการลบทั้งหมดซึ่งก็คือ ผลรวมของจำนวนเต็มทั้งหมดในเศษส่วนต่อเนื่อง - และนั่นคือสิ่งที่องค์ประกอบของฟังก์ชั่นTr@*ContinuedFractionคำนวณ! (สำหรับตัวอย่างที่กำหนด 1.35 จะได้คำตอบของความต้องการ OP เนื่องจากสแควร์สุดท้ายมีขนาดใหญ่พอที่จะนับสแควร์ทั้งหมด แต่Tr@*ContinuedFraction[1001/1000]ตัวอย่างเช่นให้ผลตอบแทน1001เนื่องจากมันนับหนึ่งสแควร์ขนาดใหญ่และ 1,000 1x1000 สแควร์เล็กทั้งหมด .)


1
ขณะนี้เป็นที่น่าสนใจแน่นอนป้ายที่ไม่ใช่การแข่งขันที่สงวนไว้สำหรับภาษาที่ใหม่กว่าความท้าทาย เป็นอิสระจากที่คำตอบทั้งหมดจะต้องแก้ปัญหาความท้าทาย ดังนั้นคำตอบนี้ควรจะถูกลบจริงๆ คุณจะสามารถสร้างขึ้นใหม่จากรายการเศษส่วนต่อเนื่องที่จะตัดออกเพื่อให้สิ่งนี้กลายเป็นวิธีแก้ปัญหาที่น่าสนใจ แต่ก็ใช้ได้เช่นกัน?
Martin Ender

1
ฉันมีอาการทางจิตที่จะเกาเมื่อเขียนคำตอบนี้ แต่ฉันยอมรับว่านี่เป็นคำตอบที่คุ้มค่าตามมาตรฐานของชุมชน (ขอบคุณสำหรับข้อเสนอแนะที่อ่อนโยนและแม่นยำของคุณ!) หาก TPTB รู้สึกว่าการลบการล่าช้าออกไปเป็นเวลา 24 ชั่วโมงฉันอาจจะสามารถบ่นวิธีที่จะให้คำตอบที่ถูกต้อง ... ถ้าไม่ใช่ลบออกไปและไม่มีความรู้สึกลำบาก
Greg Martin

3

Mathematica, 64 53 ไบต์

({t=1,#}//.{a_,b_}/;1000a*b>#:>Sort@{++t;a,b-a};t-1)&

โซลูชัน C-style ที่มีความยาวเท่ากัน:

(For[t=a=1;b=#,1000a*b>#,If[a>b,a-=b,b-=a];++t];t-1)&

2

C (GCC / Clang) 61 59 ไบต์

c,k;f(m,n){for(k=m*n;m*n/k;m>n?(m-=n):(n-=m))++c;return c;}

การป้อนข้อมูลเป็นจำนวนเต็ม (ความกว้างและความสูง) f(1999,1000)โดยจุดเช่น

ฉันหวังว่าบางคนสามารถบันทึกหนึ่งไบต์ที่ผลัก C เข้าไปในคลับขนาด 58 ไบต์ได้ ;)


แนะนำให้ลบวงเล็บไปรอบ ๆm-=n
ceilingcat

1

C, 59 ไบต์

s,a,n=1e3;C(m){for(a=m;m*n>a;s++)m>n?m-=n:(n-=m);return s;}

ลองออนไลน์

อินพุตเป็นจำนวนเต็มซึ่งเป็นอัตราส่วนความกว้าง / ความสูงเป็นพันส่วน (เช่น 1002 สำหรับ 1.002: 1)

เวอร์ชันที่ไม่ดี

int C(int m)
{
    int n = 1000;
    int a = m;
    int s = 0;

    while (m * n > a)
    {
        if (m > n)
            m -= n;
        else
            n -= m;

        s++;
    }

    return s;
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.