Kase Kazık Yüksekliğini Hesapla


19

Kase Kazık Yüksekliği

Bu bulmacanın amacı, bir kase yığını yüksekliğini hesaplamaktır.

Bir kase yığını

Bir kase, kalınlığı olmayan radyal simetrik bir cihaz olarak tanımlanır. Siluet şekli eşit bir polinomdur. Yığın, her biri eşit bir polinom ile ilişkili olan ve bir katsayı listesi olarak girdi olarak verilen bir yarıçap listesi ile tanımlanır (örneğin, liste 3.1 4.2polinom 3.1x2+4.2x4 temsil eder ).

Polinom keyfi bir dereceye sahip olabilir. Basitlik için, yığının yüksekliği en üstteki kasenin merkezinin yüksekliği olarak tanımlanır (bir örnek için Örnek 3'teki çizime bakın).

Test senaryoları biçimindedir radius:coeff1 coeff2 ...: her satır, kabın yarıçapını temsil eden bir kayan sayı ile başlar, ardından bir kolon ve çift güçler için katsayıları içeren, güç 2 ile başlayarak (sıfır sabit kısım ima edilir) . Örneğin, çizgi 2.3:3.1 4.2yarıçapı 2.3ve şekil-polinomunu tanımlar 3.1 * x^2 + 4.2 * x^4.

örnek 1

42:3.141

Tek bir kazanın yüksekliği olmadığı için sıfır yükseklikte bir yığın tarif eder.

ÖRNEK 2

1:1 2
1.2:5
1:3

yükseklik yığınını tanımlar 2.0(çizime bakınız).

Üç kase bir yığın arsa

ÖRNEK 3

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

Yükseklik 0.8 yığını tarif eder (arsadaki yeşil oka bakınız).

Üç kase bir yığın arsa

Bu kod golf, bu yüzden en kısa kod kazanır.

Ben referans kodu .

Düzenle:

Referans uygulaması, polinomların köklerini hesaplamak için bir kütüphaneye dayanmaktadır. Bunu da yapabilirsiniz ama buna gerek yok. Referans uygulaması sadece (oldukça iyi) bir sayısal yaklaşım olduğundan, ortak kayan nokta toleransları içinde doğru sonuçlar üreten herhangi bir kodu kabul edeceğim.

<ε

Bu bulmacanın bir başka çeşidi, kaseleri yeniden sıralayarak yüksekliği en aza indirmektir. Hızlı bir çözüm olup olmadığından emin değilim (sanırım NP zor). Herkes daha iyi bir fikre sahipse (ya da NP tamlığını ispatlayabilirse), lütfen bana söyleyin!


Yorumlar uzun tartışmalar için değildir; bu sohbet sohbete taşındı .
Mego

Referans kodunuzda, vücudunun is_maximumörneğin olması gerektiğine inanıyorum return evaluate(differentiate(shape_0), root) > 0.0. Şu anda, ddher zaman 0 (kökler için) döndürmesi gereken kökü (şekiller arasındaki farkın türevi) kullanarak değerlendirir . Nokta hatalarını Kayan nedeniyle, sonuç bazen olumlu değerdir yakın kodu doğru ya da daha doğru bir sonuç verir, bu yüzden de 0 olarak bazı zaman. 1:0.2, 1:0.1 0.2Çıktı alması gereken girişi kontrol edin0.0125
fazlalık

@ redundancy aslında gereksizdir. Max y değeri seçilir ve 0 her zaman karşılaştırma değerlerinde olur.
Nick Kennedy

2
Örnek 3'te, nihai yükseklik olmalıdır 0.801. Son iki kase yarıçapta temas eder 0.1.
attinat

Evet, aynı sonucu aldım.
Joel

Yanıtlar:


6

Jöle , 54 53 bayt

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

Çevrimiçi deneyin!

Bağımsız değişken olarak kase listesini yukarıdan aşağıya formatta alan [[b1_radius, b1_coef1, ...], [b2_radius, b2_coef1, ...]]ve üst kabın alt kısmının y konumunu döndüren monadik bir bağlantı .

Artık minimum yarıçap dışındaki yerlerdeki kaseleri doğru şekilde işler.

açıklama

Yardımcı bağlantı: lkaseleri 1'den itibaren temsil eden polinomların katsayılarındaki farklılıkları ve sağ argümanını rminimum yarıçapı sol argüman olarak alır; iki kasenin buluştuğu maksimum y değerini döndürür

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

Ana bağlantı, bir kase yığınını argüman olarak alır ve üst kase tabanının y değerini döndürür

Œ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 referansı

Son olarak, ana sorun için @pasbi'nin dahil ettiği Python referansının TIO versiyonu. Stdin'den okuyor.


1
Dili hiç anlamıyorum. Açıklamaya göre, sadece her bir kase çiftini (r1, p1)ve (r2, p2)noktada karşılaştırıyor min(r1, r2)musunuz? Eğer öyleyse, bu yanlış bir çözüm olurdu çünkü iki kase 0ve arasında temas edebilir min(r1, r2)). Sen bulmalıyız max(p1(x)-p2(x), 0)tüm aralığı boyunca [0, min(r1, r2)]için x. Bu nedenle @ pasbi'nin referans çözümü, yerel maksimumu bulmak için türevleri hesaplar.
Joel

@ Joe şimdi düzeltildi. Tüm orijinal test vakalarına değindi min(r1, r2). Bu, @ attinat'ın ek görevini çözüyor
Nick Kennedy

1
Zamanınız varsa, golf dili hakkında bilgi sahibi olmayanlar için kodun yorumlanmış bir versiyonunu görmek güzel olurdu.
Joel

@Joel zaman aldığımda yapacak
Nick Kennedy

2

Python 3 + numpy + scipy, 248 240 bayt

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

Çevrimiçi deneyin!

@Xnor sayesinde -8 bayt

İşlev [radius, polynomial]giriş olarak bir çift listesi alır ve küme yüksekliğini döndürür.

Bu çözüm, türevleri kullanarak maksimum değeri hesaplamaması dışında referans koduyla hemen hemen aynı algoritmayı kullanır. Bu arada, Python'da yerleşik numpyve scipyfonksiyonlar kullanılarak yazılmıştır . Çözülmemiş versiyon aşağıda gösterilmiştir. Bu, fikri daha kısa sürede yakalamak için daha kısa bir sürüm isteyenler için referans kodunun alternatif bir versiyonu olarak hizmet eder.

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

Çevrimiçi deneyin!


Boşluktan tasarruf etmek için, iki nokta üst üste işaretinden sonra satırına döngü ekleyebilir ve i=0isteğe bağlı bir argüman olarak koyabilirsiniz .
xnor

@xnor Ah, teşekkürler. Birkaç bayt 200 + bayt çözümde kaydetmek çok değişmez çünkü bu golf için çok fazla çaba koymak vermedi. Ve bu hesaplamayı önemli ölçüde basitleştirebilecek daha iyi bir algoritma yok gibi görünüyor.
Joel

Teknik olarak bu, başlıkta Python3 + numpy + sympy olarak tanımlanmalıdır çünkü ikisi de Python3 temel kurulumunun bir parçası değildir.
Nick Kennedy

@NickKennedy Teşekkürler. Açıklama güncellendi.
Joel

1

Wolfram Dili (Mathematica) , 104 93 bayt

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

Çevrimiçi deneyin!

{radius, polynomial}x

Sembolik çıktı yerine ondalık için, bunun yerine NMaxValuekullanın (veya yalnızca Nsonucu arayı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 , 451436 bayt

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

Çevrimiçi deneyin!

Çevrimiçi deneyin!

Genel olarak, Jelly cevabımın bir R portunu konuşmakla birlikte, taban R'nin polinomların köklerini bulmak için bir işlevi olmadığından, bu, bulunan yöntem kullanılarak uygulanır polynom::solve.polynomial.

Yığının üstünden alt kısmına sayısal vektörlerin listesini alan bir işlev.

15 bayt golf için @RobinRyder'a teşekkürler!


Burada olan her şeyi anlamıyorum (açıklama iyi olurdu!), Ama burada 436 baytlık bir sürüm var .
Robin Ryder
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.