Restoranımı nereye koymalıyım?


15

Bir restoranın sahibisiniz. Cartesia'da y ekseni olarak bilinen tek bir ana yolun bulunduğu yeni bir bölgede açıyorsunuz. Restoranınızı, restoranınızdan ve o bölgedeki evlerin her birinden toplam mesafeyi en aza indirecek şekilde yerleştirmek istiyorsunuz.

Giriş :

Girdi

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

burada her ev formda bir koordinattır x y. Her birim bir kilometreyi temsil eder.

Girdiyi dize olarak alabilir veya girdiyi bağımsız değişkenler olarak seçtiğiniz formatta alan bir işlev sağlayabilirsiniz.

Çıktı : Restoranınızın y koordinatı (unutmayın, y ekseninde bulunacaktır). Aslında, yolun kenarında yer alacak, ancak fark göz ardı edilebilir.

N'inci ev ise Esasen, h_nve Duzaklık fonksiyonu, daha sonra bulmak istediğiniz kşekilde D(h_0, (0, k)) + D(h_1, (0, k)) + D(h_2, (0, k)) + ... + D(h_n, (0, k))minimize edilir.

Mesafenin, müşterinin evinden restorana tam olarak düz bir çizgide seyahat ettiği gibi hesaplandığını unutmayın. (x, y)Restoranınıza olan mesafe budur sqrt(x^2 + (y - k)^2).

Çıktı en az 2 ondalık basamağa kadar doğru olmalıdır.

Çıktı bir dize olarak yazdırılabilir veya işlevden döndürülebilir.

Örnek giriş / çıkış:

Input:
2
5.7 3.2
8.9 8.1
Output:
5.113013698630137

Bu örnekteki toplam mesafe yaklaşık 15.4003kilometredir.

Bu kod golf - en kısa kod kazanır.

PS: Ayrıca sadece kaba kuvvet değil, matematiksel bir çözümle de ilgileniyorum. Golf kodunu kazanmaz ama bazı upvotes alır. Örnek sorunu nasıl yaptım:

A noktasının A (5.7, 3.2) ve B'nin B (8.9, 8.1) 'de olmasına izin verin. (0, k) C'deki çözelti noktasını C olsun. A 'yı (-5.7, 3.2) yapmak için y ekseni üzerine A yansıtın. A 'ile C arasındaki mesafe A ile C arasındaki mesafeye eşittir. Bu nedenle, problem A noktasına C' CB 'ye indirgenecek şekilde azaltılabilir. Açıkçası, bu A'B çizgisinde yer alan C noktası olacaktır.

Bunun 3 veya daha fazla noktaya genelleme yapıp yapmayacağını bilmiyorum.


Mesafe fonksiyonu için hangi metrik kullanılır D? Öklid?
Reto Koradi

1
Tek bir ana yol olmasına rağmen, bir müşterinin evinden restorana düz bir çizgide gittiğini düşünüyor muyuz? Yoksa önce doğrudan y eksenine mi gidiyorlar? (Ya da başka bir deyişle, D için Öklid ya da Manhattan mesafesini kullanıyor muyuz?)
trichoplax

1
(Bu, örnekten çıkarılabilir, ancak açıkça belirtilmesi iyi olur.)
trichoplax

@trichoplax Öklid? Öklid ne demek sqrt(diffX^2 + diffY^2)? Sonra Öklid. Senaryoya mükemmel bir şekilde uymadığını biliyorum ancak müşterinin evinden bir şekilde düz bir şekilde seyahat ettiğini varsayalım.
soktinpk

5
Evlerin karmaşık düzlemdeki konumlarını temsil eden karmaşık sayıların bir listesi olarak girdi kabul edilebilir mi?
lirtosiast

Yanıtlar:


27

Cı, 315 302 bayt

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

Bu güzel olmaktan uzak ve kısa da değil. Uzunluk yarışmasını kazanamayacağımı düşündüm, (teorik) doğruluk yarışmasını kazanmaya çalışabilirim! Kod muhtemelen bruteforce çözümünden bir veya iki daha hızlı bir büyüklük sırasıdır ve biraz matematiksel tomfoolery'ye dayanır.

g(N,S)Konut sayısını Nve bir dizi konutu girdi olarak alan bir fonksiyon tanımlarız S[][2].

Burada bir test çantasıyla çözülüyor:

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

Hangi çıktılar:

5.11301369863013732697

Uyarı: Eksiksiz bir anlayış için biraz matematik bilgisi gerekli olabilir!

Şimdi matematik hakkında konuşalım.

İstediğimiz noktaya (0, k)ve bir eve olan mesafeyi biliyoruz i:

D_i'un tanımı

Ve böylece toplam mesafe Ddan nşöyle evlerin tanımlanabilir:

D'un tanımı

Yapmak istediğimiz şey, buna göre bir türev alarak kve ona eşit yaparak bu işlevi en aza indirmektir 0. Hadi deneyelim. Türevlerinin Daşağıdaki gibi tanımlanabileceğini biliyoruz :

D türevi

Ama her birinin ilk kısmi türevi Dioldukça kötü ...

Di'nin Türevi 1

Ne yazık ki, olsa bile n == 2, bu türevleri ayarlamak 0ve çözmek kçok hızlı bir şekilde felaket olur. Biraz yaklaşım gerektirse bile daha sağlam bir yönteme ihtiyacımız var.

Taylor Polinomlarına girin.

'Nin D(k0)tüm Dtürevlerinin değerini ve değerini k0bilirsek D, Taylor Serisi olarak yeniden yazabiliriz :

Taylor Series'un tanımı

Şimdi, bu formülün içinde bir sürü şey var ve türevleri oldukça hantal olabilir, ama şimdi polinom yaklaşımımız var D !

Biraz analiz Dyaparak Di, daha önce olduğu gibi türevlerini değerlendirerek sonraki iki türevini buluruz :

Di türevi 2

Di türevi 3

Kesmeleri ve türevleri değerlendirerek, şimdi Dformun 3. derece polinomu olarak yaklaşık olarak tahmin edebiliriz :

Yaklaşık D şekli

A, B, C, DSadece gerçek sayılar nerede .

Şimdi bu biz en aza indirebilir. Bir türev alıp 0'a eşitlediğimizde, formun bir denklemiyle sonuçlanır:

D 'yaklaşımı

Analiz ve ikameleri yaparken, aşağıdaki formülleri buluruz a, b, and c:

Değeri

B değeri

C değeri

Şimdi sorunumuz bize ikinci dereceden formülle verilen 2 çözüm sunuyor:

K değeri

Tüm formül kyazmak için büyük bir yük olurdu, bu yüzden bunu burada ve kodda parçalar halinde yapıyoruz.

Daha yüksek kolanın her zaman yaklaşık değerimizin minimum mesafesine yol açacağını bildiğimizden D(bu kağıdın marjının içermesi yeterli olmadığına dair gerçekten muhteşem bir kanıtım var ...) çözümler.

Son bir sorun var. Doğruluk amaçları için, k0en azından cevabın olmasını beklediğimiz yerdeki ballpark'ta olan bir ile başlamamız gerekir. Bu amaçla, kodum her evin y değerlerinin geometrik ortalamasını seçer.

Fail-safe olarak, yerine yine 9 kez tüm sorunu tekrar k0birlikte kdoğruluğunu sağlamak için, her işleminde.

Kaç yineleme ve kaç türevin gerçekten gerekli olduğu konusunda matematik yapmadım, ancak doğruluğu onaylayana kadar dikkatli olmayı tercih ettim.

Bunu benimle yaptıysan, çok teşekkür ederim! Umarım anlarsın ve eğer hatalar (çok fazla olan, çok yorgunum) tespit ederseniz, lütfen bana bildirin!


2
Birincisi, matematiğinizin açıklamasını görmek isterim.
DLosc

2
@DLosc Senin dileğin benim emrimdir.
BrainSteel

4
Bu gerçekten harika. Newton'un Metodunu denemeyi düşündüm, ancak Taylor serisini düşünmedim.
DLosc

5
Keşke bunu daha fazla değerlendirebilseydim.
Alex

@AlexA. Keşke beni de daha fazla değerlendirebilseydiniz; D Bir gün içinde Fermat'ın son teorem referansını kaldıracağım ve bir kanıtla değiştireceğim. Bir tanesini bulur bulmaz.
BrainSteel

13

TI-BASIC, 20

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

Bu formda TI-83 veya 84 serisi hesap makinenizin ana ekranına girdi alır ( 2:yok sayılacak bir ilk yazabilirsiniz ):

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

Evler her zaman başlangıç ​​noktasından bir milyar km'den daha azsa, E99, 18 bayt boyutunda E9 ile değiştirilebilir.

Mathematica tabanlı bir golf dili olsaydı, bu zorluğu 10-14 baytta kazanabilirdi.


10

Mathematica, 42 bayt

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

Bu, ev koordinatları olarak çiftlerin listesini alan ve istenen y koordinatını döndüren anonim bir işlevdir.

Oldukça basit bir uygulama. Bu harita Norm[#-{0,k}]&(belirsiz bir noktasına olan mesafeyi hesaplar olan koordinat her ev üzerine {0,k}y ekseni üzerine) ile hepsini Özetle Tr[...](eşdeğerdir iz için Total1 d listeleri için). Ardından Minimize, bu tutarın minimumunu bulmak için uygun olanı kullanırız k. Bu formun bir sonuç verir {distance, {k -> position}ihtiyacımız böylece, k/.Last@ayıklamak için positionaradığımız.


6

Pyth, 33 bayt

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

Bu kaba kuvvet çözümüdür: .001 km çözünürlük ile restoranın mümkün olan tüm yerlerini evlere olan toplam mesafelerine göre sıralar, ardından en az toplam mesafeye sahip olanı seçer. Evin konumlarını STDIN'de yüzen 2 giriş listesinin bir listesi olarak alır.

Gösteri.

Çözünürlük aynı kod uzunluğunda 1e-2 km'den 1e-10 km'ye kadar, ancak çalışma zamanında üstel yavaşlamalarla ayarlanabilir.

Bu biraz daha golf olabilir gibi hissediyorum, daha sonra tekrar bakacağım.


2
Lol! Çözümümü kopyaladın mı? ;-)
Jakube

@Jakube Eşleştirme ^T3özellikle etkileyici.
isaacg

Gerçekten bir kayan nokta aralığına ihtiyacımız var.
Maltysen

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

Golf odası bir sürü bu şüpheli bıraktı. Hemen hemen bir kaba kuvvet yöntemi. Bunu yapmanın daha güzel bir yolunu bulmak istiyorum. Ben Geometric Means yardımcı olabilir ama ne yazık ki hayır.

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

Test sürüşü

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

Bir ilgi konusu olarak, dikkate alınması gereken sadece iki ev varsa, aşağıdakiler kabul edilebilir bir sonuç verecektir. Ancak üçe düşüyor. Şu anda daha fazla ilerleyemem, ama buradaki beyinlerin bazılarının onunla bir şeyler yapabileceğini düşündüm.

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

2

MATLAB, 42

Girdiyi aşağıdaki gibi almak uygunsa

I=[5.7 3.2
    8.9 8.1]

o zaman bu ifade

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

döner 5.113014445748538.

Utanmadan Thomas Kwa'nın yöntemini çalarak, en az 30'a indirebilirsin:

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

1
nEv sayısı ile çalışmak uzatılabilir mi? Sorunun istediği bu.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

Evet, herhangi bir sayıda satırla çalışır I.
David
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.