Kareleri sayın


18

Meydan okuma

Origami (katlama kağıdı) yaratıcı bir sanat şeklidir. Bildiğim kadarıyla, Origami ustası kare kağıdı tercih ediyor. En baştan başlayalım - dikdörtgen bir kağıdı kare bir kağıda dönüştürün.

Böylece kağıt karelere bölünür. Mevcut şekliyle daha kısa bir kenarı paylaşan en büyük kareyi adım adım kaldırıyoruz (aşağıdaki resme bakın). Ve bir adımdan sonra kalan kısım daha küçük veya eşitse 0.001 * (area of the original paper), kağıt daha fazla bölünemez. Sonunda hiçbir şeyin kalmaması mümkündür.

Göreviniz, işlem sırasında kaç kare yapıldığını hesaplamaktır. Son adımda kağıdın bölünememesine neden olan kare çıktıya sayılır.

Örnek ( 1.350genişlik / yükseklik kağıdı ), çıktı 10'dur:

dilim örneği

Giriş ve çıkış

Girdi: dikdörtgen kağıt için en / boy oranı, bir ila ondalık (veya nokta olmadan bir tam sayı) 1.002için 1.999asgari bir adım 0.001. Oranı tanımlayan diğer makul formatları da kullanabilirsiniz. Sadece cevabında bahset.

Çıktı: kare sayısı, bir tamsayı.

Örnek G / Ç

Bir eşleme biçimi sayfanın düzenli kalması için kullanılırken, kodunuzun bir liste girişini desteklemesi veya bir eşleme işlevi olması gerekmez.

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

Tüm cevapların listesi

@LuisMendo sayesinde, cevapların grafiği burada.

grafik

Uyarılar

  • Bu bir kod golfü yani kısa kod kazanıyor
  • Standart boşluklara dikkat edin
  • Girdi ve çıktı ile nasıl başa çıkılacağına karar verme özgürlüğünüz ancak standart kısıtlamalara uymaları gerekir.

Bu arada...

  • Meydan okuma hakkında net olmayan bir şeyiniz varsa yorum yapın
  • Şahsen golf dili kullanıyorsanız cevabınızın bir açıklama içerdiğini öneririm
  • @GregMartin sayesinde, meydan okuma için iyi bir matematik açıklaması için cevabını okuyun.

Örnek Kod

İşte C ++ kodunun ungolfed sürümü:

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

Örnek kodla ilgili tüm hesaplamalar, kapsanan 6 ondalık basamak doğruluğuna ihtiyaç duyar float.


Oranı oluşturan iki sayı girdi olarak kullanılabilir mi?
Luis Mendo

@LuisMendo evet, isteğiniz gibi.
Keyu Gan

2
Temiz meydan okuma!
Kusur

5
Cevapların listesi güzel bir grafik
Luis Mendo

1
@KeyuGan Tabii ki, devam et! Başka bir formatta bir sürüme ihtiyacınız varsa bana bildirin
Luis Mendo

Yanıtlar:


2

MATL , 19 bayt

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

Giriş, iki sayının orijinal oranı tanımlayan bir dizisidir, örneğin [1, 1.009]. (Sayıların sıralanması veya bir tanesinin 1 olması gerekmez.)

Çevrimiçi deneyin!

açıklama

`        % 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 bayt

Bazı ustaca iyileştirmeler için @xnor'a teşekkürler!

(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

Çevrimiçi deneyin!


Düsünülürse m==nsonunda olabilir 1>0kalan tek olasılık olduğu için. Ya da, belki de davalar burada bir bağlamaya izin verecek şekilde yeniden düzenlenebilir.
xnor

Aslında, eşitlik davası gerekli mi? Eğer n>mşekilde genişletilir n>=mve ilk onay yazılır e>m*n*1000, o vermelidir 1eşitlik.
xnor

@xnor İyi fikir, teşekkürler!
flawr

1
Muhafızlar 56 için hareket:(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

Vay, d<-n-mas kullanarak otherwisegerçekten temiz !!!
flawr

4

JavaScript (ES6), 59 58 bayt

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

Ölçek


4

Mathematica, rakip olmayan (21 bayt)

Bu cevap rekabet etmiyor çünkü sorulan asıl soruya cevap vermiyor! Ancak sorunun bir varyantını cevaplıyor ve bazı ilginç matematiği vurgulamak için bir bahane sunuyor.

Tr@*ContinuedFraction

Giriş olarak pozitif bir rasyonel sayı alan (pay ve payda orijinal kağıdın boyutlarını temsil eden) ve pozitif bir tamsayı döndüren sembolik fonksiyon. Örneğin, Tr@*ContinuedFraction[1350/1000]döner10 . (ContinuedFraction hassasiyet sorunları nedeniyle kayan nokta sayılarına farklı davranır, bu nedenle bu bağlamda girdi olarak rasyonel bir sayıya ihtiyaç vardır.)

Problemde açıklanan geometrik prosedürün ilginç bir yorumu (bir dikdörtgeni tekrar tekrar kesmek), en büyük ortak bölenleri bulmak için Öklid algoritmasının bir uygulamasıdır! Oranın içindeki sorunun kendisinin örneğini düşünün1.35(1350,1000) boyutlarında bir kağıt parçasıyla modellenebilir. Her kare kesildiğinde, daha küçük sayı daha büyük sayıdan çıkarılır; dolayısıyla bu örnekte elde edilen dikdörtgenlerin boyutları (350.1000), sonra (350.650), sonra (350.300), sonra (50.300), sonra (50.250) ve (50.200) ve (50.150) ve (50.100) ve (50, 50) ve aynı zamanda (50,0) son kareyi kendimizden uzaklaştırdığımızda. Öklid algoritması tam olarak bu şekilde çalışır (bölünme ve tekrarlanan çıkarma arasındaki farkı modulo) ve aslında 50'nin gerçekten 1350 ve 1000'in GCD'si olduğunu görüyoruz.

Tipik olarak Öklid algoritmasında, kişi bu ara boyutları takip eder ve çıkarma sayısını atar; ancak, fark çok küçük hale gelmeden önce bir sayıyı kaç kez çıkardığımızı ve çıkardığımız şeyi değiştirmemiz gerektiğini dönüşümlü olarak kaydedebiliriz. Bu kayıt yöntemi tam olarak rasyonel bir sayının devam eden kesiridir. (Asla sona ermeyen irrasyonel sayıların devam eden kesirleri de süper serindir, ancak burada ilgili değildir.) Örneğin, 1350/1000 örneğinde, 1000 1kez, sonra 350 2kez, sonra 300 1kez, sonra 50 6kez çıkardık; bu nedenle devam eden 1350/1000 fraksiyonudur {1,2,1,6}. Matematiksel olarak, 1350 1/ 1000'i + 1 / ( 2+ 1 / ( 1+ 1 /6)) girin.

Dolayısıyla, bu sorun için, kareler belirli bir harmandan daha küçük olduğunda durmazsanız, ancak durmadan önce sonlu birçok kareyi sayarsanız, toplam kare sayısı toplam çıkarma sayısına eşittir, yani devam eden kesitteki tüm tamsayıların toplamı - ve tam olarak fonksiyonların bileşiminin Tr@*ContinuedFractionhesapladığı şey budur! (Verilen örnek 1.35 için, OP'nin istediği cevabı alır, çünkü son kare tüm karelerin sayılabileceği kadar büyüktür. Ancak Tr@*ContinuedFraction[1001/1000], örneğin, 1001büyük bir kareyi ve küçük 1x1000 karelerin 1000'ini saydığı için verimler .)


1
Bu gerçekten ilginç olsa da, rakip olmayan etiket, meydan okumadan daha yeni diller için ayrılmıştır . Bundan bağımsız olarak, tüm cevapların meydan okumayı çözmesi gerekir. Bu nedenle, bu cevap gerçekten silinmelidir. Eşit derecede ilginç ama geçerli bir çözüme dönüştürülebilmesi için nerede kesileceği sürekli kesir listesinden yeniden oluşturabilir misiniz?
Martin Ender

1
Bu yanıtı yazarken çizmek için zihinsel bir kaşıntı yaşadım, ancak bunun toplum standartlarına göre silinmeye değer bir cevap olduğunu kabul ediyorum. (Nazik ancak doğru geri bildiriminiz için teşekkür ederiz!) TPTB, silinmesini 24 saat ertelemek istiyorsa, doğru cevabı vermek için yaklaşımı kolaylaştırabilirim ... değilse, silin ve sert duygular yok.
Greg Martin

3

Mathematica, 64 53 bayt

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

Zorunlu (C tarzı) bir çözüm tam olarak aynı uzunluktadır:

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

2

C (GCC / Clang), 61 59 bayt

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

Girdi, nokta gibi iki tamsayıdır (genişlik ve yükseklik) f(1999,1000).

Umarım birisi C'yi 58 bayt kulübe iterek bir bayt kurtarabilir. ;)


Parantezleri çıkarmayı önerinm-=n
ceilingcat

1

C, 59 bayt

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

Çevrimiçi deneyin

Girdi, binde bir olarak genişlik / yükseklik oranı olan bir tamsayıdır (örn. 1.002: 1 için 1002).

Ungolfed sürümü

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;
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.