Calcola l'altezza del mucchio di scodelle


19

Altezza del catino

L'obiettivo di questo puzzle è calcolare l'altezza di una pila di ciotole.

Una pila di ciotole

Una ciotola è definita come un dispositivo radialmente simmetrico senza spessore. La sua sagoma è un polinomio uniforme. Lo stack è descritto da un elenco di raggi, ciascuno associato a un polinomio pari, dato come input come un elenco di coefficienti (ad esempio, l'elenco 3.1 4.2rappresenta il polinomio ).3.1x2+4.2x4

Il polinomio può avere un grado arbitrario. Per semplicità, l'altezza della pila è definita come l'altitudine del centro della ciotola più in alto (vedere la trama dell'esempio 3 per un'illustrazione).

I casi di test sono nel formato radius:coeff1 coeff2 ...: ogni riga inizia con un numero float che rappresenta il raggio della ciotola, seguito da due punti e un elenco separato da spazi contenente i coefficienti per le potenze pari, a partire dalla potenza 2 (è implicita la parte zero costante) . Ad esempio, la linea 2.3:3.1 4.2descrive una ciotola di raggio 2.3e il polinomio di forma 3.1 * x^2 + 4.2 * x^4.

Esempio 1

42:3.141

descrive una pila di altezza zero poiché una singola ciotola non ha altezza.

Esempio 2

1:1 2
1.2:5
1:3

descrive una pila di altezza 2.0(vedi trama).

Trama di una pila di tre ciotole

Esempio 3

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

descrive una pila di altezza 0,8 (vedi freccia verde nella trama).

Trama di una pila di tre ciotole

Questo è il codice golf, quindi vince il codice più corto.

Ho un codice di riferimento .

Modificare:

L'implementazione di riferimento si basa su una libreria per calcolare le radici dei polinomi. Puoi farlo anche tu, ma non è necessario. Poiché l'implementazione di riferimento è solo un'approssimazione numerica (abbastanza buona), accetterò qualsiasi codice che produca risultati corretti entro tolleranze in virgola mobile comuni.

L'idea conta. Non mi importa se ci sono piccoli errori .<ε

Un'altra variante di questo puzzle è di minimizzare l'altezza riordinando le ciotole. Non sono sicuro che esista una soluzione rapida (suppongo sia NP-difficile). Se qualcuno ha un'idea migliore (o può dimostrare la completezza NP), per favore dimmelo!


I commenti non sono per una discussione estesa; questa conversazione è stata spostata in chat .
Mego

Nel tuo codice di riferimento, credo che il corpo di is_maximumdovrebbe essere ad es return evaluate(differentiate(shape_0), root) > 0.0. Attualmente, valuta la radice usando dd(derivata della differenza tra le forme), che dovrebbe sempre restituire 0 (per le radici). A causa di errori in virgola mobile, il risultato è occasionalmente un valore positivo vicino a 0, motivo per cui il codice restituisce un risultato corretto o più accurato qualche volta. Controllare l'input 1:0.2, 1:0.1 0.2che dovrebbe emettere0.0125
ridondanza il

@redundancy è in realtà ridondante comunque. Viene scelto il valore massimo y e 0 sarà sempre nei valori di confronto.
Nick Kennedy,

2
Nell'esempio 3, l'altezza finale dovrebbe essere 0.801. Le ultime due ciotole si toccano al raggio 0.1.
attinat

Sì, ho ottenuto lo stesso risultato.
Gioele il

Risposte:


6

Gelatina , 54 53 byte

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

Provalo online!

Un collegamento monadico che prende come argomento l'elenco delle ciotole dall'alto verso il basso nel formato [[b1_radius, b1_coef1, ...], [b2_radius, b2_coef1, ...]]e restituisce la posizione y del fondo della ciotola superiore.

Ora gestisce correttamente le ciotole che si incontrano in luoghi diversi dal raggio minimo.

Spiegazione

Helper link: prende come argomento sinistro lle differenze nei coefficienti dei polinomi che rappresentano le ciotole da 1 in su e il suo argomento destro rnel raggio minimo; restituisce il valore y massimo nel punto in cui le due ciotole si incontrano

  $                   | 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

Collegamento principale, prende una pila della ciotola come argomento e restituisce il valore y della base della ciotola superiore

Œ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

Riferimento Python

Infine, ecco una versione TIO del riferimento Python che @pasbi ha incluso per il problema principale. Legge da stdin.


1
Non capisco affatto la lingua. Sulla base della spiegazione, sembra che si confronti solo ogni coppia di coppe (r1, p1)e (r2, p2)al punto min(r1, r2)? Se è così, sarebbe una soluzione sbagliata perché due ciotole possono toccare tra 0e min(r1, r2)). È necessario trovare max(p1(x)-p2(x), 0)su tutta la gamma [0, min(r1, r2)]per x. Ecco perché la soluzione di riferimento di @ pasbi calcola i derivati ​​per trovare il massimo locale.
Gioele il

@Joel risolto ora. Tutti i casi di test originali toccati min(r1, r2). Questo ora risolve la sfida aggiuntiva di @ attinat
Nick Kennedy il

1
Sarebbe bello vedere una versione commentata del codice per coloro che non hanno conoscenza del linguaggio del golf, se hai tempo.
Gioele il

@Joel lo farà quando avrò tempo
Nick Kennedy il

2

Python 3 + numpy + scipy, 248 240 byte

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

Provalo online!

-8 byte grazie a @xnor

La funzione accetta un elenco di [radius, polynomial]coppie come input e restituisce l'altezza della pila.

Questa soluzione utilizza più o meno lo stesso algoritmo del codice di riferimento, tranne per il fatto che non calcola il massimo utilizzando i derivati. Nel frattempo, è scritto usando built-in numpye scipyfunzioni in Python. La versione non golfata è mostrata di seguito. Questo serve come una versione alternativa del codice di riferimento per coloro che desiderano una versione più breve per catturare rapidamente l'idea.

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

Provalo online!


Per salvare su spazi bianchi, puoi mettere il tutto per il ciclo sulla sua linea dopo i due punti e metterlo i=0come argomento opzionale.
xnor

@xnor Ah, grazie. Non ho fatto troppi sforzi per giocare a golf perché il salvataggio di un paio di byte in una soluzione da 200 + byte non lo cambierebbe molto. E sembra che non esiste un algoritmo migliore per questo che possa semplificare significativamente il calcolo.
Gioele il

Tecnicamente questo dovrebbe essere descritto nell'intestazione come Python3 + numpy + sympy poiché nessuno dei due fa parte dell'installazione di base di Python3.
Nick Kennedy,

@NickKennedy Grazie. Descrizione aggiornata.
Gioele il

1

Wolfram Language (Mathematica) , 104 93 byte

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

Provalo online!

{radius, polynomial}x

Per l'output decimale anziché simbolico, utilizzare NMaxValueinvece (o semplicemente chiamare Nil risultato).

(* 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 byte

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)}

Provalo online!

Provalo online!

Parlando in generale di una porta R della mia risposta Jelly, sebbene poiché la base R non ha alcuna funzione per trovare le radici dei polinomi, questo viene implementato usando il metodo trovato in polynom::solve.polynomial.

Una funzione che prende un elenco di vettori numerici dall'alto verso il basso della pila.

Grazie a @RobinRyder per giocare a golf con 15 byte!


Non capisco tutto quello che sta succedendo qui (la spiegazione sarebbe buona!), Ma qui c'è una versione da 436 byte .
Robin Ryder, il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.