Où dois-je mettre mon restaurant?

15

Vous êtes propriétaire d'un restaurant. Vous ouvrez dans une nouvelle zone de Cartesia où il n'y a qu'une seule route principale, connue sous le nom d'axe y. Vous souhaitez placer votre restaurant de manière à minimiser la distance totale entre votre restaurant et chacune des maisons de cette zone.

Entrée :

L'entrée sera

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

où chaque maison est une coordonnée dans le formulaire x y. Chaque unité représente un kilomètre.

Vous pouvez prendre l'entrée sous forme de chaîne ou fournir une fonction qui prend l'entrée, dans le format que vous choisissez, comme arguments.

Sortie : la coordonnée y de votre restaurant (rappelez-vous, elle sera située sur l'axe y). En fait, il sera situé sur le côté de la route, mais la différence est négligeable.

Essentiellement, si la nième maison est h_net Dest la fonction de distance, alors vous voulez trouver kcelle qui D(h_0, (0, k)) + D(h_1, (0, k)) + D(h_2, (0, k)) + ... + D(h_n, (0, k))est minimisée.

Notez que la distance est calculée comme si le client se rendait exactement en ligne droite de sa maison au restaurant. C'est la distance de (x, y)votre restaurant sqrt(x^2 + (y - k)^2).

La sortie doit être précise à au moins 2 décimales.

La sortie peut être imprimée sous forme de chaîne ou renvoyée par la fonction.

Exemple d'entrée / sortie:

Input:
2
5.7 3.2
8.9 8.1
Output:
5.113013698630137

La distance totale dans cet exemple est d'environ 15.4003kilomètres.

C'est le golf de code - le code le plus court gagne.

PS Je m'intéresse aussi à une solution mathématique qui n'est pas seulement la force brute. Il ne gagnera pas le golf de code mais il obtiendra quelques votes positifs. Voici comment j'ai fait l'exemple du problème:

Soit le point A situé en A (5.7, 3.2) et B en B (8.9, 8.1). Soit le point de solution en (0, k) égal à C. Réfléchissez A sur l'axe des y pour faire A 'en (-5,7, 3,2). La distance de A 'à C est égale à la distance de A à C. Par conséquent, le problème peut être réduit au point C de telle sorte que A'C + CB soit minimisé. Évidemment, ce serait le point C qui se trouve sur la ligne A'B.

Je ne sais pas si cela généraliserait bien à 3 points ou plus.

soktinpk
la source
Quelle métrique est utilisée pour la fonction de distance D? Euclidienne?
Reto Koradi
1
Même s'il n'y a qu'une seule route principale, supposons-nous qu'un client voyage en ligne droite de sa maison au restaurant? Ou voyagent-ils directement vers l'axe y en premier? (Ou en d'autres termes, utilisons-nous la distance euclidienne ou Manhattan pour D?)
trichoplax
1
(Cela peut être calculé à partir de l'exemple, mais ce serait bien de le dire explicitement.)
trichoplax
@trichoplax Euclidean? Euclidien signifie- sqrt(diffX^2 + diffY^2)t -il ? Puis euclidienne. Je sais que cela ne correspond pas parfaitement au scénario, mais supposons que le client se déplace en ligne droite de sa maison.
soktinpk
5
Est-il acceptable de prendre des entrées sous forme de liste de nombres complexes représentant les positions des maisons sur le plan complexe?
lirtosiast

Réponses:

27

C, 315 302 octets

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

C'est loin d'être joli, et ce n'est pas court non plus. Je me suis dit que puisque je ne gagnerais pas le concours de longueur, je peux essayer de gagner le concours de précision (théorique)! Le code est probablement un ordre de grandeur ou deux plus rapide que la solution bruteforce, et repose sur un peu de tromperie mathématique.

Nous définissons une fonction g(N,S)qui prend en entrée le nombre de maisons N, et un tableau de maisons S[][2].

Ici, il est démêlé, avec un cas de test:

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

Quelles sorties:

5.11301369863013732697

Avertissement: La connaissance de certains calculs peut être nécessaire pour une compréhension complète!

Parlons donc des mathématiques.

Nous connaissons la distance de notre point souhaité (0, k)et d'une maison i:

Définition de D_i

Et ainsi la distance totale Ddes nmaisons peut être définie comme suit:

Définition de D

Ce que nous aimerions faire, c'est minimiser cette fonction en prenant une dérivée par rapport à ket en la réglant sur 0. Essayons. Nous savons que les dérivés de Dpeuvent être décrits comme suit:

Dérivée de D

Mais la première dérivée partielle de chacun Diest assez mauvaise ...

Dérivée 1 de Di

Malheureusement, même avec n == 2, la définition de ces dérivés 0et leur résolution kdeviennent très rapidement désastreuses. Nous avons besoin d'une méthode plus robuste, même si elle nécessite une approximation.

Entrez Taylor Polynomials.

Si nous connaissons la valeur de D(k0)ainsi que tous Dles dérivés de k0, nous pouvons réécrire Dsous forme de série Taylor:

Définition par Taylor Series

Maintenant, cette formule contient beaucoup de choses, et ses dérivés peuvent devenir assez lourds, mais nous avons maintenant une approximation polynomiale de D !

En faisant un peu de calcul, nous trouvons les deux dérivées suivantes de Den évaluant les dérivées de Di, comme précédemment:

Dérivée 2 de Di

Dérivée 3 de Di

En tronquant et en évaluant les dérivées, nous pouvons maintenant approximer Dcomme un polynôme du 3ème degré de la forme:

Forme approximative de D

A, B, C, Dsont simplement de vrais nombres.

Maintenant , ce que nous pouvons minimiser. Lorsque nous prenons une dérivée et la mettons égale à 0, nous nous retrouverons avec une équation de la forme:

Approximation de D '

En faisant le calcul et les substitutions, nous proposons ces formules pour a, b, and c:

Valeur d'un

Valeur de b

Valeur de c

Maintenant, notre problème nous donne 2 solutions données par la formule quadratique:

Valeur de k

La formule entière pour kserait un fardeau énorme à écrire, donc nous le faisons en morceaux ici et dans le code.

Puisque nous savons que le plus élevé kentraînera toujours la distance minimale de notre approximatif D(j'en ai une preuve vraiment merveilleuse, que la marge de cet article est insuffisante pour contenir ...), nous n'avons même pas à considérer le plus petit des les solutions.

Un dernier problème demeure. Pour des raisons de précision, il est nécessaire que nous commencions par un k0qui est au moins dans le stade où nous attendons la réponse. À cette fin, mon code choisit la moyenne géométrique des valeurs y de chaque maison.

Comme un échec de sécurité, nous le répétons à nouveau tout le problème 9 fois, en remplaçant k0avec kà chaque itération, pour assurer l' exactitude.

Je n'ai pas fait le calcul du nombre d'itérations et du nombre de dérivés vraiment nécessaires, mais j'ai choisi de faire preuve de prudence jusqu'à ce que je puisse confirmer l'exactitude.

Si vous avez réussi cela avec moi, merci beaucoup! J'espère que vous avez compris, et si vous repérez des erreurs (dont il y en a probablement beaucoup, je suis très fatigué), faites le moi savoir!

BrainSteel
la source
2
Pour ma part, j'aimerais voir l'explication de vos mathématiques.
DLosc
2
@DLosc Votre souhait est ma commande.
BrainSteel
4
C'est vraiment merveilleux. J'ai envisagé d'essayer la méthode de Newton, mais je n'ai pas pensé à la série Taylor.
DLosc
5
J'aimerais pouvoir voter davantage.
Alex A.
@AlexA. Je souhaiterais que vous puissiez également m'exprimer davantage; D Dans un jour ou deux, je supprimerai la dernière référence de théorème de Fermat et la remplacerai par une preuve. Dès que j'en trouve un.
BrainSteel
13

TI-BASIC, 20

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

Prend des informations sur l'écran d'accueil de votre calculatrice de la série TI-83 ou 84 sous cette forme (vous pouvez taper une 2:première, qui serait ignorée):

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

Si les maisons sont toujours à moins d'un milliard de kilomètres de l'origine, E99 peut être remplacé par E9 pour une taille de 18 octets.

S'il y avait un langage de golf basé sur Mathematica, il pourrait gagner ce défi en 10-14 octets.

lirtosiast
la source
10

Mathematica, 42 octets

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

Il s'agit d'une fonction anonyme prenant une liste de paires comme coordonnées de la maison et renvoyant la coordonnée y souhaitée.

C'est une implémentation assez simple. Nous mappons Norm[#-{0,k}]&sur chaque coordonnée de la maison (qui calcule la distance à un point indéterminé {0,k}sur l'axe y) et les additionnons tous Tr[...](pour trace, ce qui équivaut à Totalpour les listes 1-d). Ensuite, nous utilisons la pratique Minimizepour trouver le minimum de cette somme k. Cela donne un résultat du formulaire {distance, {k -> position}, nous devons k/.Last@donc extraire ce positionque nous recherchons.

Martin Ender
la source
6

Pyth, 33 octets

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

Voici la solution de la force brute: il commande tous les emplacements possibles du restaurant, avec une résolution de 0,001 km, par leur distance totale des maisons, puis sélectionne celui qui a la distance totale la plus faible. Il prend les emplacements des maisons comme une liste de 2 listes d'entrées de flotteurs sur STDIN.

Manifestation.

La résolution peut être définie de 1 à 2 km à 1 à 10 km à la même longueur de code, mais avec des ralentissements exponentiels lors de l'exécution.

J'ai l'impression que cela pourrait être joué au golf un peu plus, je le reverrai plus tard.

isaacg
la source
2
Lol! Avez-vous copié ma solution? ;-)
Jakube
@Jakube La correspondance ^T3est particulièrement impressionnante.
isaacg
Nous avons vraiment besoin d'une gamme flottante.
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
diète
la source
3

R, 145 143 126

Il me reste beaucoup de terrain de golf là-dessus, je suppose. À peu près une méthode de force brute. J'aimerais trouver une meilleure façon de procéder. Je pensais que les moyens géométriques pouvaient aider, mais hélas non.

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

Essai

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

Il est intéressant de noter que s'il n'y a que deux maisons à considérer, ce qui suit donnera un résultat acceptable. Cependant, il tombe sur trois. Je ne peux pas aller plus loin pour le moment, mais je pensais que certains cerveaux ici pourraient être en mesure de faire quelque chose avec.

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

MATLAB, 42

S'il est OK de prendre l'entrée comme

I=[5.7 3.2
    8.9 8.1]

alors cette déclaration

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

retourne 5.113014445748538.

Volant sans vergogne la méthode de Thomas Kwa, vous pouvez la ramener à 30 au moins:

I=[5.7+3.2i 8.9+8.1i];
fminunc(@(y)sum(abs(I-i*y)),0)
David
la source
1
Peut-il être étendu pour fonctionner avec le nnombre de maisons? Car c'est ce que demande la question.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳
Oui, cela fonctionne avec n'importe quel nombre de lignes I .
David