Тайны туалетной бумаги

36

Сегодня вам нужно решить очень практическую задачу: сколько петель нужно, чтобы на рулон туалетной бумаги было определенное количество листов? Давайте посмотрим на некоторые факты:

  • Диаметр пустого цилиндра туалетной бумаги составляет 3,8 см
  • Длина одного листа туалетной бумаги 10см.
  • Толщина одного листа туалетной бумаги составляет 1 мм.

Прежде чем вы обернетесь вокруг цилиндра в первый раз, он имеет окружность в см 3,8 * пи. Каждый раз, когда вы обматываете лист вокруг цилиндра, его радиус увеличивается на 0,1, поэтому его окружность увеличивается на 0,2 * PI. Используйте эту информацию, чтобы узнать, сколько петель требуется для размещения n листов туалетной бумаги. (Примечание: используйте приближение числа Пи, которое по крайней мере столь же точно, как и 3.14159).

Тестовые случаи :

n = 1 :

  • 10 / (3,8 * пи) = 0,838 петель

n = 2 :

  • (Сколько полных циклов мы можем сделать?) 1 полный цикл = 3,8 * пи = 11,938.
  • (Сколько у нас осталось после 1-го цикла?) 20 - 11,938 = 8,062
  • (Какую часть второго цикла выполняет оставшаяся часть?) 8.062 / (4 * pi) = .642 цикла
  • Ответ: 1.642 петли

n = 3 :

  • 1-й полный цикл = 3,8 * пи = 11,938, 2-й полный цикл = 4 * пи = 12,566
  • 30 - 11,938 - 12,566 = 5,496
  • 5,496 / (4,2 * пи) = 0,417
  • Ответ: 2.417 петель

n = 100 => 40,874

geokavel
источник
35
Уф! 1 мм толщиной? Вы уверены, что используете туалетную бумагу, а не картон?
Цифровая травма
11
@DigitalTrauma Очевидно, что вы не знаете о тройном
сгибе
2
Исходя из предположения, что туалетная бумага не делает шагов, а постоянно увеличивает радиус, вы можете получить приближение в закрытой форме к требуемому результату. Это достаточно хорошо? nloops = sqrt(n+11.34)*0.0564189 - 0.19
flawr
2
Предлагаемый тестовый пример: 100->40.874
Деннис
1
Трехслойный картон ?! Теперь это толстый!
mbomb007

Ответы:

13

Pyth, 27 23 байта

+fg0=-QJc*.n0+18T50)cQJ

Попробуйте онлайн. Тестирование.

объяснение

                            Q = input number (implicit)
 f                 )        increment T from 1, for each T:
             +18T             add 18 to T, get radius
         *.n0                 multiply by pi to, get half the circumference
        c        50           divide by 50, get circumference in sheets
       J                      save it to J
    =-Q                       decrement Q by it
  g0                          use this T if Q is now <= 0
+                           add
                     Q        Q (now <= 0)
                    c J       divided by J (the last circumference)
                            and print (implicit)
PurkkaKoodari
источник
объяснение, пожалуйста?
Конор О'Брайен
@ CᴏɴᴏʀO'Bʀɪᴇɴ Добавлено. Объяснять Pyth всегда очень весело.
PurkkaKoodari
2
Ваше объяснение выглядит как потенциальный вывод для Surfin 'Word
geokavel
10

Haskell, 59 46 44 байта

Применяется масштабный коэффициент 5 / пи, так что бумажный цилиндр имеет окружность 19,20,21 ... см, а лист 50 / пи см.

Благодаря xnor удалось сохранить 2 байта, используя неназванную функцию.

x!s|s>x=1+(x+1)!(s-x)|1>0=s/x
(19!).(50/pi*)
Damien
источник
Довольно рекурсивный метод. Обратите внимание, что неназванные функции разрешены, даже если у вас есть другие строки (несмотря на то, что Haskell не поддерживает их), поэтому последняя строка может быть безточечной, как (19!).(50/pi*).
xnor
Вау, уносит мой подход из воды!
CR Drost
5

Haskell, 97 байт

p&((m,x):(n,y):z)|y<p=p&((n,y):z)|1>0=m+(p-x)/(y-x)
t=(&zip[0..](scanl(+)0$map(*pi)[0.38,0.4..]))

Возможно, удастся сыграть в него дальше, переместив фильтрацию от &оператора в takeWhileутверждение, но, учитывая, что это не язык игры в гольф, это кажется относительно конкурентоспособным.

объяснение

Поток длин туалетной бумаги, который содержит полные петли, сначала рассчитывается как scanl (+) 0 (map (* pi) [0.38, 0.4 ..]]. Мы заархивируем их числом полных оборотов, что также Doubleнеявно определит тип . Мы передаем это &текущему номеру, который мы хотим вычислить, позвоним p.

&обрабатывает список (Double, Double)пар справа от него (а), пропуская вперед до тех пор, пока не snd . head . tailстанет больше, чем p, в этот момент snd . headменьше, чем p.

Чтобы получить долю этой строки, которая заполнена, она затем вычисляет (p - x)/(y - x),и добавляет ее к общему количеству циклов, которые были сделаны до сих пор.

ЧР Дрост
источник
4

C ++, 72 байта

float f(float k,int d=19){auto c=d/15.9155;return k<c?k/c:1+f(k-c,d+1);}

Я использовал C ++ здесь, потому что он поддерживает аргументы функции по умолчанию, необходимые здесь для инициализации радиуса.

Кажется, что рекурсия производит более короткий код, чем использование for-loop. Также autoвместо float- на 1 байт меньше!

anatolyg
источник
1
Вы почти одурачили меня, используя dдля radius ...
Тоби Спейт
3

Луа, 82 байта

n=... l,c,p=10*n,11.938042,0 while l>c do l,c,p=l-c,c+.628318,p+1 end print(p+l/c)

Неплохо для языка общего назначения, но, конечно, не очень конкурентоспособен по отношению к выделенным языкам гольфа. Константы предварительно умножаются на пи с заданной точностью.

Криптих стоит с Моникой
источник
OP не уточнил, какие входные данные принимать, поэтому я пропустил инициализацию n, но все остальное работало бы как есть (как было?). В любом случае, теперь это происходит nиз командной строки; например, для 3 листов запустите его как lua tp.lua 3.
Криптих стоит с Моникой
Это не совсем правило этого вопроса, а общая политика. Если в вопросе не указано иное, жесткое кодирование ввода делает отправку фрагментом кода, что по умолчанию запрещено . Более подробную информацию о настройках по умолчанию для всего сайта можно найти в вики-коде code golf .
Деннис
Я знал о части «всей программы или функции», но не знал, что «жесткое кодирование ввода делает отправку фрагментом». Спасибо за разъяснение. Я думаю, что это на самом деле будет больше, как функция!
Криптих стоит с Моникой
3

JavaScript, 77 байт

function w(s,d,c){d=d||3.8;c=d*3.14159;return c>s*10?s*10/c:1+w(s-c/10,d+.2)}

Росс Брэдбери
источник
3
Добро пожаловать в PPCG! Если вы хотите, вы можете использовать JavaScript ES6 и получить это до 55 байт:w=(s,d=3.8,c=d*3.14159)=>c>s*10?s*10/c:1+w(s-c/10,d+.2)
Downgoat
3

C 87 байтов

float d(k){float f=31.831*k,n=round(sqrt(f+342.25)-19);return n+(f-n*(37+n))/(38+2*n);}

Использует явную формулу для числа целых циклов:

floor(sqrt(100 * k / pi + (37/2)^2) - 37/2)

Я заменил 100 / piна 31.831, и заменить floorс round, поворачивая досадное число -18.5к чистому -19.

Длина этих петель

pi * n * (3.7 + 0.1 * n)

После вычитания этой длины из всей длины код делит остаток на соответствующую окружность.


Просто чтобы прояснить - это решение имеет сложность O(1), в отличие от многих (всех?) Других решений. Так что это немного длиннее, чем цикл или рекурсия.

anatolyg
источник
2

C #, 113 байт

double s(int n){double c=0,s=0,t=3.8*3.14159;while(n*10>s+t){s+=t;c++;t=(3.8+c*.2)*3.14159;}return c+(n*10-s)/t;}

Ungolfed:

double MysteryToiletPaper(int sheetNumber) 
    { 
        double fullLoops = 0, sum = 0, nextLoop = 3.8 * 3.14159; 

        while (sheetNumber * 10 > sum + nextLoop) 
        { 
            sum += nextLoop; 
            fullLoops++; 
            nextLoop = (3.8 + fullLoops * .2) * 3.14159; 
        } 

        return fullLoops + ((sheetNumber * 10 - sum) / nextLoop); 
    }

Полученные результаты:

за 1 лист

0,837658302760201

за 2 листа

1,64155077524438

за 3 листа

2,41650110749198

на 100 листов

40,8737419532946

ivaan
источник
2

PHP, 101 байт

<?$p=pi();$r=3.8;$l=$argv[1]*10;$t=0;while($r*$p<$l){$t+=($l-=$r*$p)>0?1:0;$r+=.2;}echo$t+$l/($r*$p);

Ungolfed

<?
$pi = pi();
$radius = 3.8;
$length_left = $argv[1]*10;
$total_rounds = 0;
while ($radius * $pi < $length_left) {
    $total_rounds += ($length_left -= $radius * $pi) > 0 ? 1 : 0;
    $radius += .2;
}
echo $total_rounds + $length_left/( $radius * $pi );

Я чувствую, что это можно сделать немного короче, но у меня закончились идеи.

Samsquanch
источник
2

Python 3, 114 109 99 байт

Эта функция отслеживает окружность каждого слоя, пока сумма окружностей не станет больше, чем длина количества листов. Как только это произойдет, ответ:

  • Один меньше , чем число слоев , рассчитанных + длина оставшихся листов / окружность самого последнего слоя

def f(n):
    l,s=0,[]
    while sum(s)<n:s+=[.062832*(l+19)];l+=1
    return len(s)-1+(n-sum(s[:-1]))/s[-1]

Обновить

  • -10 [16-05-09] Оптимизировал мою математику
  • -5 [16-05-04] Минимизированное количество строк
NonlinearFruit
источник
1

JavaScript, 44 байта

w=(i,d=19,c=d/15.9155)=>i<c?i/c:1+w(i-c,d+1)

Я использовал идею Анатолия и перевел код на JavaScript.

ericw31415
источник
1

> <>, 46 44 байта

a*0"Gq",:&a9+*\
?\:{$-{1+{&:&+>:{:})
;>{$,+n

Ожидается, что количество листов будет присутствовать в стеке при запуске программы.

При этом используется приближение числа Пи 355/113 = 3.14159292..., сохраняемое pi/5в регистре. Окружность текущей итерации живет в стеке и pi/5добавляется к каждой итерации.

Изменить: Рефакторинг для непосредственного сохранения окружности - предыдущая версия сохраняла pi/10и начинала диаметр как 38, который был на 2 байта длиннее.

Sok
источник
0

PHP, 79 байт

function p($s,$d=3.8){$c=$d*pi();return $c>$s*10?$s*10/$c:1+p($s-$c/10,$d+.2);}

Запустить код в песочнице

Я почти полностью перевел ответ Росса Брэдбери о JavaScript в функцию PHP, которая также является рекурсивной.

Ник
источник
Пожалуйста, не копируйте другой ответ на другой язык.
R