Обчислити висоту чаші


19

Висота ворсу чаші

Мета цієї головоломки - обчислити висоту стопки чаш.

Стопка мисок

Чаша визначається як радіально симетричний пристрій без товщини. Його силуетна форма - рівномірний. Стек описується списком радіусів, кожен з яких пов'язаний з рівним многочленом, подається як вхід у вигляді списку коефіцієнтів (наприклад, список 3.1 4.2представляє многочлен ).3.1x2+4.2x4

Поліном може мати довільну ступінь. Для простоти висоту ворсу визначають як висоту в центрі самої верхньої чаші (див. Графік Прикладу 3 для ілюстрації).

Випробування складаються у форматі radius:coeff1 coeff2 ...: кожен рядок починається з числа поплавця, що представляє радіус чаші, після чого двокрапка і розділений пробілом список, що містять коефіцієнти для рівних потужностей, починаючи з потужності 2 (нульова постійна частина мається на увазі) . Наприклад, рядок 2.3:3.1 4.2описує миску радіуса 2.3та форму-многочлен 3.1 * x^2 + 4.2 * x^4.

Приклад 1

42:3.141

описує купу нульової висоти, оскільки одна чаша не має висоти.

Приклад 2

1:1 2
1.2:5
1:3

описує купу висоти 2.0(див. сюжет).

Сюжет стопки з трьох мисок

Приклад 3

1:1.0
0.6:0.2
0.6:0.4
1.4:0.2
0.4:0 10

описує купу висотою 0,8 (див. зелену стрілку на графіку).

Сюжет стопки з трьох мисок

Це кодовий гольф, тому виграє найкоротший код.

У мене є довідковий код .

Редагувати:

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

<ε

Ще один варіант цієї головоломки - мінімізувати висоту шляхом переупорядкування чаш. Я не впевнений, чи є швидке рішення (я думаю, що це важко). Якщо хтось має кращу ідею (або може довести NP-повноту), будь ласка, скажіть мені!


Коментарі не для розширеного обговорення; ця розмова переміщена до чату .
Мего

У вашому довідковому коді я вважаю, що органом is_maximumмає бути, наприклад return evaluate(differentiate(shape_0), root) > 0.0. В даний час він оцінює корінь за допомогою dd(похідна різниці між формами), яка завжди повинна повертати 0 (для коренів). У зв'язку з плаваючою точкою помилки, то результат буде іноді позитивне значення близько до 0, тому код виводить правильний або більш точний результат деякі з часу. Перевірте вхід, 1:0.2, 1:0.1 0.2який повинен вивести0.0125
надмірність

@redundancy це все-таки зайве. Вибирається значення max y, і 0 завжди буде у значеннях порівняння.
Нік Кеннеді

2
У прикладі 3 повинна бути кінцева висота 0.801. Останні дві миски торкаються за радіусом 0.1.
attinat

Так, я отримав такий же результат.
Джоель

Відповіді:


6

Желе , 54 53 байти

J×$ÆrAƑƇ«⁹;⁹*€J{ḋ⁸ŻṀ
Œcz€0ḢṂç@I0;ⱮFƲƲ€ṚṁL’R€Ɗ;+Ṁ¥¥ƒ0Ṁ

Спробуйте в Інтернеті!

Монадійне посилання, яке приймає за аргумент список чаш зверху вниз у форматі [[b1_radius, b1_coef1, ...], [b2_radius, b2_coef1, ...]]і повертає y положення нижньої частини верхньої чаші.

Тепер правильно поводиться з мисками, які зустрічаються в інших місцях, ніж мінімальний радіус.

Пояснення

Хелперна ланка: приймає за лівий аргумент lрізниці коефіцієнтів многочленів, що представляють миски від 1 вгору, а його правильний аргумент r- мінімальний радіус; повертає максимальне значення y, де зустрічаються дві чаші

  $                   | Following as a monad:
J                     | - Sequence from 1..<len(l)>
 ×                    | - Multiply (by l)
   Ær                 | Roots of polynomial
     AƑƇ              | Keep only those invariant when passed through absolute function (excludes negative, imaginary and complex numbers)
        «⁹            | Min of these filtered roots and r
          ;⁹          | Concatenate r to the list
            *€        | Each root/radius to the power of:
              J{      | - Sequence from 1..<len(l)>
                ḋ⁸    | Dot product with l
                  Ż   | Prepend zero
                   Ṁ  | Maximum

Основне посилання, бере аркуш чаші як аргумент і повертає y значення бази верхньої чаші

Œc                               | Combinations length 2
  z€0                            | Transpose each using 0 as a filler
               Ʋ€                | For each one, do the following as a monad:
     Ḣ                           | - Take the head (the radii)     
      Ṃ                          | - Minimum
       ç@     Ʋ                  | - Call the helper link with this (min radius) as right argument and the following as left argument:
         I                       |   - Increments (difference between second and first polynomial for each coefficient)
          0;Ɱ                    |   - Prepend each with a zero (odd coefficients are all zero)
             F                   |   - Flatten
                 Ṛ               | Reverse
                  ṁ    Ɗ         | Mould to the following as a monad:
                   L             | Length
                    ’            | Decrease by 1
                     R€          | Range of each (e.g. [1],[1,2],[1,2,3],[1,2,3,4]
                            ¥ƒ0  | Reduce using the following as a dyad and starting with 0
                        ;  ¥     | - Concatenate the following as a dyad
                         +       |   - Add
                          Ṁ      |   - Take the maximum
                               Ṁ | Finally take the overall maximum

Посилання Python

Нарешті, ось ТІО-версія посилання на Python, яку @pasbi включив до основної проблеми. Він читається з stdin.


1
Я мови зовсім не розумію. Виходячи з пояснення, схоже, ви порівнюєте лише кожну пару мисок (r1, p1)і (r2, p2)в точці min(r1, r2)? Якщо це так, це було б неправильним рішенням, оскільки дві тарілки можуть торкатися між 0і min(r1, r2)). Вам потрібно знайти max(p1(x)-p2(x), 0)весь діапазон [0, min(r1, r2)]для x. Ось чому еталонне рішення @ pasbi обчислює похідні для знаходження локального максимуму.
Джоель

@Joel виправлено зараз. Усі оригінальні тестові справи торкнулися min(r1, r2). Тепер це вирішує додатковий виклик @ attinat
Нік Кеннеді,

1
Було б добре побачити коментовану версію коду для тих, хто не знає мови гольфу, якщо у вас є час.
Джоель

@Joel зробить, коли я знайду час
Нік Кеннеді

2

Python 3 + numpy + scipy, 248 240 байт

from scipy.optimize import*
from numpy import*
def f(b,i=0):
 for r,c in b:p=zeros(2*len(c)+1);p[-3::-2]=c;p[-1]=h=max([0,*(-fminbound(lambda x:polyval(polysub(p,d),x),0,min(s,r),full_output=1)[1]for s,d in b[:i])]);b[i][1]=p;i+=1
 return h

Спробуйте в Інтернеті!

-8 байт завдяки @xnor

Функція приймає список [radius, polynomial]пар як вхідні дані і повертає висоту палі.

Це рішення використовує більш-менш той же алгоритм, що і контрольний код, за винятком того, що він не обчислює максимум за допомогою похідних. Тим часом він написаний за допомогою вбудованих numpyта scipyфункцій у Python. Версія без вогків показана нижче. Це служить альтернативною версією довідкового коду для тих, хто хоче, щоб коротша версія швидко захопила ідею.

from scipy.optimize import fminbound
import numpy as np

def compute_pile_height(bowl_data):
    for i, (r, curve) in enumerate(bowl_data):
        distances = [0]  # Initialize the distances array with 0 as the lower bound for max
        # Construct a complete polynominal coefficient array
        curve_poly = np.zeros(2 * len(curve) + 1)
        curve_poly[-3::-2] = curve
        
        # Iterate over all bowls under the current bowl
        for j in range(i):
            b_r, b_curve_poly = bowl_data[j]

            # Calculate the difference polynominal between the current bowl and bowl j
            diff = np.polysub(curve_poly, b_curve_poly)

            # Find the maximum height difference between bowl j and the current bowl in the range [0, min(b_r, r)]
            max_height_diff = -fminbound(lambda x:np.polyval(diff, x), 0, min(b_r, r), full_output=True)[1]
            distances.append(max_height_diff)

        # Compute the maximum distance as the height for the current bowl, 
        # update the polynominal using the height as the constant coefficient
        curve_poly[-1] = height = max(distances)

        # Update stored data for the current bowl
        bowl_data[i][1] = curve_poly
    return height

Спробуйте в Інтернеті!


Щоб заощадити на пробілі, ви можете помістити цілий цикл на його рядок після двокрапки і поставити i=0як необов’язковий аргумент.
xnor

@xnor Ах, спасибі Я не доклав надто великих зусиль для того, щоб пограти в гольф, тому що збереження пари байтів у 200 + байтному рішенні не змінило б його сильно. І здається, що для цього немає кращого алгоритму, який би міг значно спростити обчислення.
Джоель

Технічно це слід описати в заголовку як Python3 + numpy + sympy, оскільки жоден з них не є частиною базової установки Python3.
Нік Кеннеді

@NickKennedy Дякую Опис оновлено.
Джоель

1

Мова Вольфрама (Mathematica) , 104 93 байт

FoldPair[{(R=#;F=#2)&@@#2;H=Max[0,{#2-F,0<x<#~Min~R}~MaxValue~x&@@@#],#~Join~{R|H+F}}&,{},#]&

Спробуйте в Інтернеті!

{radius, polynomial}x

Для десяткової замість символічного виводу використовуйте NMaxValueнатомість (або просто зателефонуйте Nна результат).

(* Step through a list of bowls: *)
(* At each step, calls a function taking {previous-bowls-list},current-bowl *)
(*  which returns {height,{bowls-list}} *)
(* and returns the final height *)
FoldPair[
  (R=#;F=#2)&@@#2;          (*  extract Radius and Function*)
  {
    H=Max[0,                (*  Height - at least zero; the greatest of *)
      MaxValue[{#2-F,       (*   the required heights *)
          0<x<#~Min~R},x]   (*     within the relevant domain *)
      &@@@#]                (*   given all previous bowls *)
  ,
    #~Join~{R|H+F}          (*   append to list of bowls *)
  }&,
  {},                       (* initial list of bowls (empty) *)
  #                         (* list of bowls *)
]&

1

R , 451 436 байт

function(x){x=c(x[1],x);a=rev(pmax(0,c(combn(x,2,function(y,z=sapply(y,"length<-",max(lengths(y)))){z[is.na(z)]=0
b=rep(0,2*(n=nrow(z)-1))
b[2*1:n]=e=z[-1,2]-z[-1,1]
b=b*1:(2*n)
while(!c(b,1)[1])b=b[-1]
b=rev(b)
s=`if`(length(b)>1,eigen(rbind(-(b/b[1])[-1],cbind(diag(length(b)-2),0)))$va,0)
max(outer(c(pmin(abs(s[s==abs(s)]),r<-min(z[1,])),r),2*1:n,`^`)%*%e)}))))
o={}
for(i in seq(a=x[-1])){o=c(o,max(c(0,o)+a[1:i+F]));F=F+i}
max(o)}

Спробуйте в Інтернеті!

Спробуйте в Інтернеті!

Широко кажучи R-порт мого відповіді Jelly, хоча оскільки база R не має функції пошуку коренів многочленів, це реалізується за допомогою методу, знайденого в polynom::solve.polynomial.

Функція, що приймає список числових векторів від верху до низу палі.

Дякуємо @RobinRyder за те, що виграли 15 байт!


Я не розумію всього, що тут відбувається (пояснення було б добре!), Але ось версія на 436 байт .
Робін Райдер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.