レストランはどこに置けばいいですか?


15

あなたはレストランのオーナーです。y軸と呼ばれる主要道路が1つしかないデカルトの新しいエリアに開通しています。あなたのレストランとそのエリアの各家からの合計距離を最小化するようにレストランを配置したい。

入力

入力は

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

ここで、各家はフォームの座標x yです。各単位は1キロメートルを表します。

入力を文字列として取得するか、引数として選択した形式で入力を取得する関数を提供できます。

出力:レストランのy座標(y軸に配置されることに注意してください)。実際には、道路の脇にありますが、違いはごくわずかです。

n番目の家であれば基本的に、h_nかつD距離関数である、あなたが見つけたい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.4003キロメートルです。

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

PS私はまた、総当たり攻撃ではない数学的な解決策にも興味があります。それはコードゴルフに勝つことはありませんが、いくつかの賛成を得ます。以下に問題の例を示しました。

ポイントAをA(5.7、3.2)に、BをB(8.9、8.1)に置きます。(0、k)の解点をCとします。Aをy軸に反射して、A 'を(-5.7、3.2)にします。A 'からCまでの距離は、AからCまでの距離に等しい。したがって、A'C + CBが最小化されるように、問題を点Cに減らすことができます。明らかに、これはラインA'BにあるポイントCになります。

これが3ポイント以上に一般化できるかどうかはわかりません。


距離関数にはどのようなメトリックが使用されますDか?ユークリッド?
レトコラディ

1
幹線道路は1つしかありませんが、顧客が家からレストランまで直線的に移動すると仮定しますか?または、最初にy軸に直接移動しますか?(つまり、Dにユークリッド距離またはマンハッタン距離を使用しますか?)
trichoplax

1
(これは例から解決できますが、明示的に述べておくといいでしょう。)
trichoplax

@trichoplaxユークリッド?ユークリッドはどういう意味sqrt(diffX^2 + diffY^2)ですか?それからユークリッド。私はそれがシナリオに完全に適合しないことを知っていますが、顧客が彼/彼女の家から何とか直線で旅行すると仮定します。
-soktinpk

5
入力を複素平面上の家の位置を表す複素数のリストとして取得できますか?
リスト管理者

回答:


27

C、315 302バイト

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

これは見事なものとはほど遠いものであり、短いものでもありません。長さコンテストに勝つつもりはないので、(理論上の)精度コンテストに勝とうとすることができます!このコードは、おそらくブルートフォースソリューションよりも1〜2桁高速であり、数学的なごまかしに依存しています。

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の定義

したがって、家Dからの合計距離はn次のように定義できます。

Dの定義

私たちがやりたいのは、に関して導関数を取り、kに等しく設定することにより、この関数を最小化することです0。試してみよう。の導関数はD次のように記述できることを知っています。

Dの誘導体

しかし、それぞれの最初の偏微分Diはかなり悪いです...

Diのデリバティブ1

残念ながら、でもn == 2、これらの導関数をに設定し0、を解くことは、kすぐに悲惨なものになります。何らかの近似が必要な場合でも、より堅牢な方法が必要です。

テイラー多項式を入力します。

D(k0)すべてDの微分と同様にの値がわかっている場合、テイラー級数としてk0書き直すことができますD

Taylorシリーズによる定義

さて、この式にはたくさんのものがあり、その導関数はかなり扱いにくいものになりますが、今では多項式近似ができました D

少しの計算を行うと、前と同じようにのD導関数を評価することにより、次の2つの導関数を見つけますDi

Diの誘導体2

Diのデリバティブ3

切り捨てと導関数の評価によりD、次の形式の3次多項式として近似することができます。

Dの近似形式

A, B, C, D単なる実数はどこにありますか。

今、この私たちは、最小限に抑えることができます。導関数を取り、それを0に設定すると、次の形式の方程式になります。

D 'の近似

計算と置換を行って、次の式を考えますa, b, and c

の値

bの値

cの値

ここで、問題は2次式で与えられる2つの解を与えます。

kの値

全体の式はk書き出すのに大きな負担になるので、こことコードで分割して行います。

高いほどk常に近似値の最小距離が得られることがわかっているためD(これについては本当に素晴らしい証拠がありますが、この論文のマージンでは不十分です...)、小さい方を考慮する必要さえありませんソリューション。

最後の問題が残っています。正確を期すために、k0少なくとも答えが期待される場所の球場にあるから始める必要があります。この目的のために、私のコードは、すべての家のy値の幾何平均を選択します。

フェイルセーフとして、我々は交換し、再び9回全体の問題を繰り返しk0k精度を確保するために、すべての反復で。

繰り返しの回数と実際に必要な微分の数についてはまだ計算していませんが、正確性が確認できるまで慎重に判断することを選択しました。

私と一緒にそれを成し遂げたなら、どうもありがとう!あなたが理解したことを願っています、そして、もしあなたが何かの間違いを見つけたら(その多くはおそらくありますが、私は非常に疲れています)、私に知らせてください!


2
私は、あなたの数学の説明を見たいと思っています。
DLosc

2
@DLoscあなたの願いは私の命令です。
BrainSteel

4
それは本当に素晴らしいです。ニュートン法を試すことを考えましたが、テイラー級数については考えませんでした。
DLosc

5
これにもっと賛成できたらいいなと思います。
アレックスA.

@AlexA。あなたも私にもっと賛成してもらえたらいいのにと思う; D 1日かそこら以内に、フェルマーの最後の定理参照を削除し、証明に置き換える。見つけたらすぐに。
BrainSteel

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]

家が常に原点から10億km未満離れている場合、サイズが18バイトのE99をE9に置き換えることができます。

Mathematicaに基づいたゴルフ言語がある場合、10〜14バイトでこの課題に勝つことができます。


10

Mathematica、42バイト

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

これは、ペアのリストを家の座標として取得し、目的のy座標を返す匿名関数です。

それはかなり簡単な実装です。Norm[#-{0,k}]&各家の座標({0,k}y軸上の未決定の点までの距離を計算する)にマッピングし、それらを合計しますTr[...](トレースの場合はTotal1次元リストの場合と同等です)。次に、を使用してMinimize、この合計の最小値を見つけますk。これにより、フォームの結果が得られるため、探しているものを抽出する{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
笑!ソリューションをコピーしましたか?;-)
ジャクベ

@ジャクベマッチング^T3は特に印象的です。
isaacg

浮動小数点範囲が本当に必要です。
マルティセン

3

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

関心のある問題として、検討すべき家が2つしかない場合、次のことは許容できる結果を返します。しかし、それは3つになります。現時点ではこれ以上取り上げることはできませんが、ここの一部の脳はそれを使って何かできると思いました。

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

トーマス・クワの方法を恥知らずに盗むので、少なくとも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̷̰̀ĥ̷̳

ええ、それはの任意の数の行で動作しますI
デビッド
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.