C,315302字节
t,i;double o,w,h,x,y,k,a,b,c;double g(N,S)double N,S[][2];{for(t=0;t<N;t++)k+=S[t][1];k/=N;for(i=0;i<9;i++){o=w=h=0;for(t=0;t<N;t++)x=S[t][0],y=S[t][1],a=y-k,c=k*k-2*k*y+x*x+y*y,o+=-a/sqrt(x*x+a*a),w+=x*x/pow(c,1.5),h+=3*x*x*a/pow(c,2.5);a=h/2;b=w-h*k;c=o-w*k+a*k*k;k=(-b+sqrt(b*b-4*a*c))/h;}return k;}
这远非漂亮,而且也不短。我认为由于我不会赢得长度竞赛,所以我可以尝试赢得(理论上的)准确性竞赛!该代码可能比暴力破解解决方案快一个数量级或两个数量级,并且依赖于一些数学上的模棱两可。
我们定义了一个函数g(N,S)
,该函数将房屋数量N
,和房屋数组作为输入S[][2]
。
这里用一个测试用例来阐明它:
t,i;
double o,w,h,x,y,k,a,b,c;
double g(N,S)double N,S[][2];{
/* Initially, let k hold the geometric mean of given y-values */
for(t=0;t<N;t++)
k+=S[t][1];
k/=N;
/* We approximate 9 times to ensure accuracy */
for(i=0;i<9;i++){
o=w=h=0;
for(t=0;t<N;t++)
/* Here, we are making running totals of partial derivatives */
/* o is the first, w the second, and h the third*/
x=S[t][0],
y=S[t][1],
a=y-k,
c=k*k-2*k*y+x*x+y*y,
o+=-a/sqrt(x*x+a*a),
w+=x*x/pow(c,1.5),
h+=3*x*x*a/pow(c,2.5);
/* We now use these derivatives to find a (hopefully) closer k */
a=h/2;
b=w-h*k;
c=o-w*k+a*k*k;
k=(-b+sqrt(b*b-4*a*c))/h;
}
return k;
}
/* Our testing code */
int main(int argc, char** argv) {
double test[2][2] = {
{5.7, 3.2},
{8.9, 8.1}
};
printf("%.20lf\n", g(2, test));
return 0;
}
哪个输出:
5.11301369863013732697
警告:可能需要一些微积分知识才能完全理解!
因此,让我们谈谈数学。
我们知道从我们想要的点(0, k)
到一所房子的距离i
:
因此,D
到n
房屋的总距离可以定义如下:
我们想做的是通过对求导数k
并将其设置为等于来最小化此函数0
。让我们尝试一下。我们知道的导数D
可以描述如下:
但是每个的一阶偏导数都Di
非常糟糕...
不幸的是,即使有了n == 2
,将这些导数设置为0
并求解也k
很快成为灾难性的。即使需要某种近似,我们也需要一种更可靠的方法。
输入泰勒多项式。
如果我们知道的D(k0)
所有D
导数的值以及k0
,我们可以重写D
为泰勒级数:
现在,这个公式中包含了很多东西,其导数可能非常笨拙,但是现在我们有了一个多项式近似 D
!
进行微积分,我们D
通过评估的导数来找到的下两个导数Di
:
通过截断和求导数,我们现在可以近似D
为以下形式的三阶多项式:
哪里A, B, C, D
是实数?
现在,这个我们可以最小化。当我们取一个导数并将其设置为0时,我们将得出以下形式的方程:
在进行演算和替换时,我们得出以下公式a, b, and c
:
现在我们的问题为我们提供了由二次公式给出的2个解:
k
要写出整个公式,将是沉重的负担,因此我们在此处和在代码中逐段进行。
因为我们知道较高的值k
总是会导致我们近似的最小距离D
(我对此有一个真正的绝妙的证明,但本文的空白不足以容纳...),我们甚至不必考虑较小的值。解决方案。
最后一个问题仍然存在。为了准确起见,有必要从k0
至少在我们期望答案所在的范围开始的a开始。为此,我的代码选择了每个房屋的y值的几何平均值。
作为故障保护,我们将整个问题再次重复9次,替换k0
为k
在每次迭代,以确保准确性。
我还没有算出真正需要多少次迭代和多少次导数的数学运算,但是我选择谨慎行事直到确定准确性为止。
如果您能与我一起度过难关,非常感谢!希望您能理解,如果发现任何错误(可能有很多错误,我很累),请告诉我!
D
?欧几里得?