我应该把餐厅放在哪里?


15

您是一家餐厅的所有者。您将在笛卡尔的一个新区域中打开,那里只有一条主要道路,称为y轴。您要放置餐厅,以使与餐厅和该区域中每个房屋的总距离最小化。

输入

输入将是

n, the number of houses
house1
house2
house3
...
houseN

其中每个房子都是形式上的坐标x y。每个单位代表一公里。

您可以将输入作为字符串,也可以提供一个函数,将选择的任何格式的输入作为其参数。

输出:您餐厅的y坐标(请记住,它将位于y轴上)。实际上,它位于路边,但差异可以忽略不计。

从本质上讲,如果第n个房子是h_nD是距离函数,那么你要找到k这样D(h_0, (0, k)) + D(h_1, (0, k)) + D(h_2, (0, k)) + ... + D(h_n, (0, k))被最小化。

请注意,距离的计算方式就像客户从他们的房屋到餐厅的直线一样。那是(x, y)到餐厅的距离sqrt(x^2 + (y - k)^2)

输出应精确到至少2个小数位。

输出可以打印为字符串,也可以从函数返回。

输入/输出示例:

Input:
2
5.7 3.2
8.9 8.1
Output:
5.113013698630137

在此示例中,总距离约为15.4003km。

这就是代码高尔夫-最短的代码胜利。

PS我也对数学解决方案感兴趣,这不仅仅是蛮力的。它不会赢得代码高尔夫,但是会得到一些赞誉。这是我如何处理示例问题:

设点A位于A(5.7,3.2),B位于B(8.9,8.1)。设(0,k)处的解点为C。在y轴上反射A以使A'为(-5.7,3.2)。从A'到C的距离等于从A到C的距离。因此,可以将问题减小到点C,从而使A'C + CB最小。显然,这将是A'B线上的点C。

我不知道这是否可以概括为3点或更多点。


距离函数使用什么度量D?欧几里得?
Reto Koradi 2015年

1
即使只有一条主干道,我们是否假设客户从他们的房子到餐厅直线行驶?还是它们首先直接行进到y轴?(或者换句话说,我们是否使用欧几里得距离或曼哈顿距离作为D?)
trichoplax

1
(这可以从示例中得出,但是明确声明会很好。)
trichoplax

@trichoplax欧几里得?欧几里得是sqrt(diffX^2 + diffY^2)什么意思?然后是欧几里得。我知道这并不完全适合这种情况,但假设客户以某种方式从他/她的房屋直线行驶。
soktinpk

5
将输入作为表示房屋在复杂平面上的位置的复数列表是否可以接受?
lirtosiast 2015年

Answers:


27

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_i的定义

因此,Dn房屋的总距离可以定义如下:

D的定义

我们想做的是通过对求导数k并将其设置为等于来最小化此函数0。让我们尝试一下。我们知道的导数D可以描述如下:

D的导数

但是每个的一阶偏导数都Di非常糟糕...

Di的导数1

不幸的是,即使有了n == 2,将这些导数设置为0并求解也k很快成为灾难性的。即使需要某种近似,我们也需要一种更可靠的方法。

输入泰勒多项式。

如果我们知道的D(k0)所有D导数的值以及k0,我们可以重写D为泰勒级数:

由泰勒级数定义

现在,这个公式中包含了很多东西,其导数可能非常笨拙,但是现在我们有了一个多项式近似 D

进行微积分,我们D通过评估的导数来找到的下两个导数Di

Di的导数2

Di的导数3

通过截断和求导数,我们现在可以近似D为以下形式的三阶多项式:

D的近似形式

哪里A, B, C, D是实数?

现在,这个我们可以最小化。当我们取一个导数并将其设置为0时,我们将得出以下形式的方程:

D'的近似值

在进行演算和替换时,我们得出以下公式a, b, and c

一个的值

b的值

c的值

现在我们的问题为我们提供了由二次公式给出的2个解:

k的值

k要写出整个公式,将是沉重的负担,因此我们在此处和在代码中逐段进行。

因为我们知道较高的值k总是会导致我们近似的最小距离D(我对此有一个真正的绝妙的证明,但本文的空白不足以容纳...),我们甚至不必考虑较小的值。解决方案。

最后一个问题仍然存在。为了准确起见,有必要从k0至少在我们期望答案所在的范围开始的a开始。为此,我的代码选择了每个房屋的y值的几何平均值。

作为故障保护,我们将整个问题再次重复9次,替换k0k在每次迭代,以确保准确性。

我还没有算出真正需要多少次迭代和多少次导数的数学运算,但是我选择谨慎行事直到确定准确性为止。

如果您能与我一起度过难关,非常感谢!希望您能理解,如果发现任何错误(可能有很多错误,我很累),请告诉我!


2
我想一看您对数学的解释。
DLosc 2015年

2
@DLosc您的愿望是我的命令。
BrainSteel 2015年

4
真是太棒了。我考虑过尝试牛顿法,但没有想到泰勒级数。
DLosc 2015年

5
我希望我能对此再投票。
Alex A.

@AlexA。希望您也能给我更多的评价; D在一天左右的时间内,我将删除费马的最后一个定理参考,并用证明代替。只要我找到一个。
BrainSteel 2015年

13

TI-BASIC,20岁

fMin(sum(abs(iX-Ans)),X,~E99,E99

以这种形式在TI-83或84系列计算器的主屏幕上输入(您可以输入2:第一个,将被忽略):

{5.7+3.2i,8.9+8.1i}:[program name]

如果房屋始终距离原点不到十亿公里,则可以用E9替换E99,以保留18个字节的大小。

如果有一种基于Mathematica的高尔夫语言,则可以10到14个字节来赢得这项挑战。


10

Mathematica,42个字节

k/.Last@Minimize[Tr[Norm[#-{0,k}]&/@#],k]&

这是一个匿名函数,将成对列表作为房屋坐标并返回所需的y坐标。

这是一个相当简单的实现。我们映射Norm[#-{0,k}]&到每个房屋坐标(计算到{0,k}y轴上未确定点的距离),并将它们全部加起来Tr[...](对于跟踪,相当于Total一维列表)。然后,我们使用便捷工具Minimize在中找到该总和的最小值k。这给出了form的结果{distance, {k -> position},因此我们需要k/.Last@提取position所需的内容。


6

Pyth,33个字节

hosm.a,d,0NQcR^T3rhKSms*^T3ekQheK

这是蛮力解决方案:它按距离餐厅的总距离对餐厅的所有可能位置(分辨率为.001 km)进行排序,然后选择距离最小的餐厅。它以房屋位置作为STDIN上2个花车入口列表的列表。

示范。

可以在相同的代码长度下将分辨率设置为从1e-2 km到1e-10 km的任何地方,但是运行时会出现指数级下降。

我觉得可以再打些高尔夫球,以后再看。


2
大声笑!您复制了我的解决方案吗?;-)
Jakube 2015年

@Jakube匹配^T3特别令人印象深刻。
isaacg 2015年

我们确实需要一个浮动范围。
马蒂森(Maltysen)2015年

3

蟒蛇2,312

from math import*;A,L,p=[map(float,raw_input().split()) for i in range(input())],lambda a:a[1],0.001
def R(m,M,s):
 while m<=M:yield m;m+=s
m=min(A,key=L)[1];M=max(A,key=L)[1];r=(m+M)/2;s=r-m
while s>p:D={y:sum([sqrt(X*X+(Y-y)**2)for X,Y in A])for y in R(r-s,r+s,s*p)};r=min(D,key=D.get);s*=p;m=r-s;M=r+s
print r

3

R,145 143 126

我怀疑这还剩下很多高尔夫球场。蛮力法。我想找到一种更好的方法来做到这一点。我虽然“几何平均数”可能有所帮助,但是可惜没有。

r=sapply(seq(min((p=matrix(scan(),nr=2))),max(p),.001),function(X,p)c(X,sum((p[1,]^2+(p[2,]-X)^2)^.5)),p);r[1,order(r[2,])[1]]

测试运行

> r=sapply(seq(min((p=matrix(scan(),nr=2))),max(p),.001),function(X,p)c(X,sum((p[1,]^2+(p[2,]-X)^2)^.5)),p);r[1,order(r[2,])[1]]
1: 5.7 3.2
3: 8.9 8.1
5: 
Read 4 items
[1] 5.113
> 

出于兴趣考虑,如果仅考虑两栋房屋,以下将返回可接受的结果。但是,它落在三个方面。目前,我无法采取任何进一步的措施,但我认为这里的某些大脑可能能够对此做些事情。

p=matrix(scan(),nr=2);weighted.mean(p[2,],sum(p[1,])-p[1,])

2

MATLAB,42岁

如果可以,则输入为

I=[5.7 3.2
    8.9 8.1]

然后这句话

fminunc(@(y)sum(hypot(I(:,1),I(:,2)-y)),0)

返回5.113014445748538

无耻地窃取Thomas Kwa的方法,您至少可以将其降低到30:

I=[5.7+3.2i 8.9+8.1i];
fminunc(@(y)sum(abs(I-i*y)),0)

1
可以扩展以与n房屋数量一起使用吗?既然是这个问题要问。
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳ 2015年

是的,它适用于中的任意数量的行I
戴维(David)
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.