Порахуйте квадрати


18

Виклик

Орігамі (складаний папір) - це творча форма мистецтва. Наскільки мені відомо, майстер Орігамі вважає за краще квадратний папір. Почнемо з початку - перетворіть прямокутний папір у квадратний.

Так папір ділиться на квадрати. Крок за кроком видаляємо найбільший квадрат, який розділяє один коротший край із поточною формою (див. Малюнок нижче). І якщо частина, що залишилася після одного кроку, менша або дорівнює 0.001 * (area of the original paper), папір більше не можна розділяти. Цілком можливо, що нарешті нічого не залишається.

Ваше завдання - обчислити, скільки квадратів зроблено під час процесу. Квадрат на останньому кроці, який робить папір неможливим розділити, враховується у вихід.

Приклад (папір 1.350ширини / висоти), вихід 10:

приклад фрагмента

Вхід і вихід

Введення: співвідношення ширини / висоти для прямокутного паперу, один десятковий (або ціле число без крапки) від 1.002до 1.999з мінімальним кроком 0.001. Ви також можете використовувати будь-який інший розумний формат, що описує співвідношення. Просто згадайте про це у своїй відповіді.

Вихід: число квадратів, одне ціле число.

Приклад вводу / виводу

Формат відображення використовується для того, щоб сторінка була охайною, тоді як ваш код не повинен підтримувати введення списку і не бути функцією відображення.

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.


Чи можна два числа, що утворюють відношення, використовувати як вхідні дані?
Луїс Мендо

@LuisMendo так, як ваше бажання.
Кейу Ган

2
Охайний виклик!
дефект

5
У списку відповідей виходить хороший графік
Луїс Мендо

1
@KeyuGan Звичайно, вперед! Повідомте мене, чи потрібна вам версія з іншим форматом
Луїс Мендо

Відповіді:


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

Хаскелл , 71 70 65 63 62 61 58 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

Математика, неконкурсна (21 байт)

Ця відповідь є неконкурентоспроможною, оскільки не відповідає фактичному заданому питанню! Але це відповідає на варіант питання і дає привід підкреслити цікаву математику.

Tr@*ContinuedFraction

Символічна функція, що приймає як вхідне додатне раціональне число (чисельник і знаменник представляють розміри оригінального паперу) і повертає додатне ціле число. Наприклад, Tr@*ContinuedFraction[1350/1000]повертає 10. (по- ContinuedFractionрізному діє на числа з плаваючою комою через питання точності, тому для цього потрібне раціональне число.)

Цікавою інтерпретацією описаної в задачі геометричної процедури (відрізання квадратів прямокутника багаторазово) є те, що це реалізація алгоритму Евкліда для пошуку найбільших загальних дільників! Розглянемо приклад у самому питанні із співвідношенням1.35, яку можна було б змоделювати за допомогою аркуша паперу з розмірами (1350,1000). Щоразу, коли квадрат відрізається, менша кількість віднімається від більшої кількості; тому отримані прямокутники в цьому прикладі мають розміри (350,1000), потім (350,650), потім (350 300), потім (50 300), потім (50,250) і (50,200) і (50,150) і (50,100) і (50, 50), а також (50,0), коли ми відбираємо у себе останній квадрат. Саме так діє алгоритм Евкліда (за модулем різниця між діленням і повторним відніманням), і ми дійсно бачимо, що 50 - це дійсно GCD 1350 і 1000.

Зазвичай в алгоритмі Евкліда відслідковуються ці проміжні розміри і відкидається кількість віднімань; проте можна по черзі записувати, скільки разів ми віднімали одне число від іншого, перш ніж різниця стане занадто малою, і ми повинні переключити те, що ми віднімаємо. Цей спосіб запису - це саме тривала частка раціонального числа. (Продовження дробів ірраціональних чисел, які ніколи не закінчуються, також є супер крутими, але тут не доречно.) Наприклад, у прикладі 1350/1000 ми відняли 1000 1разів, потім 350 2разів, потім 300 1разів, потім 50 6разів; тому тривала фракція 1350/1000 становить {1,2,1,6}. Математично ми переписали 1350/1000 як 1+ 1 / ( 2+ 1 / ( 1+ 1 /6)), що ви можете перевірити.

Отже, для цієї проблеми, якщо ви не зупиняєтесь, коли квадрати стають меншими за певну межу, а просто підраховуєте всі кінцево багато квадратів до її зупинки, то загальна кількість квадратів дорівнює загальній кількості віднімань, що означає сума всіх цілих чисел у триваючому дробі - і саме це Tr@*ContinuedFractionобчислює склад функцій ! (Для наведеного прикладу 1.35, він отримує відповідь на бажання ОП, оскільки кінцевий квадрат є достатньо великим, щоб було підраховано всі квадрати. Але Tr@*ContinuedFraction[1001/1000], наприклад, виходить 1001, оскільки він нараховує один величезний квадрат і всі 1000 малих 1х1000 квадратів .)


1
Незважаючи на те, що це дійсно цікаво, марка , яка не конкурує, зарезервована для мов, які є новими, ніж виклик . Незалежно від цього всі відповіді дійсно потребують вирішення проблеми. Отже, цю відповідь слід справді видалити. Чи вдалося б вам реконструювати зі списку фракцій, де продовжуватись, де його відрізати, щоб це можна було перетворити на не менш цікаве, але дійсне рішення?
Мартін Ендер

1
Під час написання цієї відповіді у мене виникло душевне свербіння, але я погоджуюся, що це відповідь, гідна видалення відповідно до стандартів громади. (Дякую за ваш ніжний, але точний відгук!) Якщо TPTB відчуває, що затримує його видалення на 24 години, я, можливо, зможу виконати підхід, щоб отримати правильну відповідь ... якщо ні, видаліть і не відчуваючи важких почуттів.
Грег Мартін

3

Математика, 64 53 байти

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

Імперативне рішення (у стилі С) точно такої ж довжини:

(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
roofcat

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;
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.