ボウルパイルの高さを計算する


19

ボウル杭高さ

このパズルの目標は、ボウルの山の高さを計算することです。

ボウルのスタック

ボウルは、厚さのない放射状に対称なデバイスとして定義されます。そのシルエット形状は偶数多項式です。スタックは、それぞれが偶数の多項式に関連付けられた半径のリストで記述され、係数のリストとして入力として与えられます(たとえば、リスト3.1 4.2は多項式表します)。3.1x2+4.2x4

多項式の次数は任意です。簡単にするために、パイルの高さは一番上のボウルの中心の高度として定義されます(例については例3のプロットを参照)。

テストケースの形式はradius:coeff1 coeff2 ...次のとおりです。各行はボウルの半径を表す浮動小数点数で始まり、コロンと、べき乗の係数を含むスペースで区切られたリストが続きます。 。たとえば、線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つのボウルのスタックのプロット

例3

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

高さ0.8のパイルを示します(プロットの緑の矢印を参照)。

3つのボウルのスタックのプロット

これはコードゴルフなので、最短のコードが勝ちます。

私が持っている参照コードを

編集:

リファレンス実装は、ライブラリを使用して多項式の根を計算します。あなたもそれを行うことができますが、する必要はありません。参照実装は(非常に良い)数値近似にすぎないため、一般的な浮動小数点の許容範囲内で正しい結果を生成するコードを受け入れます。

アイデアは重要です。小さなerrosがあるかどうかは気にしません。<ε

このパズルのもう1つのバリエーションは、ボウルを並べ替えて高さを最小化することです。高速な解決策があるかどうかはわかりません(NPハードだと思います)。誰かがより良いアイデアを持っている場合(または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とにかく実際には冗長です。最大y値が選択され、0は常に比較値になります。
ニックケネディ

2
例3では、最終的な高さはである必要があります0.801。最後の2つのボウルは半径で接触し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は最小半径を取ります。2つのボウルが交わる最大の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リファレンス

最後に、主な問題のために@pasbiが含めたPython参照のTIOバージョンがあります。stdinから読み取ります。


1
私は言語をまったく理解していません。あなたが唯一の各ボウルのペアを比較するような説明に基づいて、それが見える(r1, p1)(r2, p2)の点でmin(r1, r2)?その場合、2つのボウルがとの間に触れる可能性があるため、これは間違った解決策に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

オンラインでお試しください!

@xnorのおかげで-8バイト

この関数は、[radius, polynomial]ペアのリストを入力として受け取り、パイルの高さを返します。

このソリューションは、導関数を使用して最大値を計算しないことを除いて、参照コードとほぼ同じアルゴリズムを使用します。一方、Pythonの組み込み関数numpyscipy関数を使用して記述されています。未使用のバージョンを以下に示します。これは、短いバージョンでアイデアをすばやくキャプチャしたい人のための参照コードの代替バージョンとして機能します。

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

オンラインでお試しください!


空白を節約するために、コロンの後の行にforループ全体を置きi=0、オプションの引数として置くことができます。
xnor

@xnorあ、ありがとう。200バイト以上のソリューションで数バイトを節約してもそれほど変化しないので、私はこれをゴルフにあまり努力しませんでした。そして、計算を大幅に簡素化できる、これより優れたアルゴリズムはないようです。
ジョエル

技術的には、どちらも基本Python3インストールの一部ではないため、ヘッダーではPython3 + numpy + sympyとして記述する必要があります。
ニックケネディ

@NickKennedyありがとう。説明が更新されました。
ジョエル

1

Wolfram言語(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}バツ

シンボリック出力の代わりに10進数の場合は、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

R451 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ポートです。ただし、ベースRには多項式の根を見つける機能がないため、これはにある方法を使用して実装されpolynom::solve.polynomialます。

杭の上から下へ数値ベクトルのリストを取る関数。

15バイトのゴルフをしてくれた@RobinRyderに感謝します!


ここで起こっていることすべてを理解しているわけではありませんが(説明はいいでしょう!)、ここに436バイトバージョンがあります。
ロビンライダー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.