计算碗桩高度


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完整性),请告诉我!


评论不作进一步讨论;此对话已转移至聊天
Mego

在您的参考代码中,我认为的正文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。最后两个碗半径相碰0.1
attinat

是的,我得到了相同的结果。
乔尔

Answers:


6

果冻54 53字节

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

在线尝试!

一个monadic链接,以格式从上到下的碗列表作为参数,[[b1_radius, b1_coef1, ...], [b2_radius, b2_coef1, ...]]并返回顶碗底部的y位置。

现在可以正确处理在最小半径以外的地方相遇的碗。

说明

Helper链接:将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参考

最后,这是@pasbi包含的主要问题的Python参考的TIO版本。它从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的其他挑战
Nick Kennedy

1
如果有时间的话,很高兴为那些不懂高尔夫球语言的人看到代码的注释版本。
乔尔

如果有时间,@ Joel会做
Nick Kennedy

2

蟒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]将成对的列表作为输入并返回堆高。

该解决方案使用与参考代码大致相同的算法,只是它不使用导数来计算最大值。同时,利用被写入内置numpyscipy功能在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

在线尝试!


为了节省空格,您可以将整个for循环放在冒号之后的行上,并i=0作为可选参数。
xnor

@xnor啊,谢谢。我没有花太多力气去打高尔夫球,因为在200字节以上的解决方案中保存几个字节不会带来太大变化。似乎没有一种更好的算法可以大大简化计算。
乔尔

从技术上讲,这应该在标头中描述为Python3 + numpy + sympy,因为两者都不是基本Python3安装的一部分。
尼克·肯尼迪

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

在线尝试!

在线尝试!

概括地说,我的Jelly答案是R端口,尽管由于基R没有找到多项式根的功能,所以可以使用中找到的方法来实现polynom::solve.polynomial

该函数从堆的顶部到底部获取数值向量的列表。

感谢@RobinRyder打高尔夫球15个字节!


我不了解这里发生的一切(解释会很好!),但这是436字节的版本
罗宾·赖德
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.