¿Dónde debo poner mi restaurante?

15

Eres el dueño de un restaurante. Está abriendo en una nueva área en Cartesia donde solo hay una carretera principal, conocida como el eje y. Desea colocar su restaurante de manera que minimice la distancia total desde su restaurante y cada una de las casas en esa área.

Entrada :

La entrada será

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

donde cada casa es una coordenada en la forma x y . Cada unidad representa un kilómetro.

Puede tomar la entrada como una cadena o proporcionar una función que tome la entrada, en cualquier formato que elija, como sus argumentos.

Salida : la coordenada y de su restaurante (recuerde, se ubicará en el eje y). En realidad, se ubicará al costado de la carretera, pero la diferencia es insignificante.

Esencialmente, si la enésima casa es h_ny Des la función de distancia, entonces desea encontrar ktal queD(h_0, (0, k)) + D(h_1, (0, k)) + D(h_2, (0, k)) + ... + D(h_n, (0, k)) esté minimizada.

Tenga en cuenta que la distancia se calcula como si el cliente viaja en línea recta desde su casa hasta el restaurante. Esa es la distancia desde (x, y)su restaurante essqrt(x^2 + (y - k)^2) .

La salida debe tener una precisión de al menos 2 decimales.

La salida puede imprimirse como una cadena o puede devolverse desde la función.

Ejemplo de entrada / salida:

Input:
2
5.7 3.2
8.9 8.1
Output:
5.113013698630137

La distancia total en este ejemplo es de aproximadamente 15.4003kilómetros.

Este es el código de golf: el código más corto gana.

PD: También estoy interesado en una solución matemática que no sea solo la fuerza bruta. No ganará el código de golf, pero obtendrá algunos votos positivos. Así es como hice el problema de ejemplo:

Deje que el punto A se ubique en A (5.7, 3.2) y B en B (8.9, 8.1). Deje que la solución apunte a (0, k) sea C. Refleje A sobre el eje y para hacer A 'en (-5.7, 3.2). La distancia de A 'a C es igual a la distancia de A a C. Por lo tanto, el problema puede reducirse al punto C de manera que se minimice A'C + CB. Obviamente, este sería el punto C que se encuentra en la línea A'B.

No sé si esto se generalizaría bien a 3 o más puntos.

soktinpk
fuente
¿Qué métrica se usa para la función de distancia D? Euclidiana?
Reto Koradi
1
A pesar de que solo hay una carretera principal, ¿suponemos que un cliente viaja en línea recta desde su casa hasta el restaurante? ¿O viajan directamente al eje y primero? (O, en otras palabras, ¿usamos la distancia euclidiana o de Manhattan para D?)
trichoplax
1
(Esto se puede resolver a partir del ejemplo, pero sería bueno tenerlo explícitamente.)
trichoplax
@trichoplax Euclidiana? ¿Euclidiana significa sqrt(diffX^2 + diffY^2)? Entonces euclidiano. Sé que no encaja perfectamente en el escenario, pero supongo que el cliente viaja en línea recta de alguna manera desde su casa.
soktinpk
55
¿Es aceptable tomar datos como una lista de números complejos que representan las posiciones de las casas en el plano complejo?
lirtosiast

Respuestas:

27

C, 315 302 bytes

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

Esto está lejos de ser bonito, y tampoco es corto. Pensé que como no voy a ganar el concurso de longitud, ¡puedo intentar ganar el concurso de precisión (teórica)! El código es probablemente un orden de magnitud o dos más rápido que la solución de fuerza bruta, y se basa en un poco de tontería matemática.

Definimos una función g(N,S)que toma como entrada el número de casas N, y un conjunto de casas.S[][2] .

Aquí está descifrado, con un caso de prueba:

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

Qué salidas:

5.11301369863013732697

Advertencia: ¡Se requiere conocimiento de algunos cálculos para una comprensión completa!

Entonces, hablemos de las matemáticas.

Conocemos la distancia desde nuestro punto deseado (0, k)y una casa i:

Definición de D_i

Y así, la distancia total Ddesde las ncasas se puede definir de la siguiente manera:

Definición de D

Lo que nos gustaría hacer es minimizar esta función tomando una derivada con respecto a k y estableciéndola igual a 0. Vamos a intentarlo. Sabemos que las derivadas de Dse pueden describir de la siguiente manera:

Derivada de D

Pero la primera derivada parcial de cada uno Dies bastante mala ...

Derivado 1 de Di

Desafortunadamente, incluso con n == 2 , establecer estos derivados 0y resolverlos se kvuelve desastroso muy rápidamente. Necesitamos un método más robusto, incluso si requiere alguna aproximación.

Entra Taylor Polynomials.

Si conocemos el valor D(k0)y todos Dlos derivados de k0, podemos reescribir Dcomo una serie de Taylor:

Definición por serie Taylor

Ahora, esta fórmula tiene un montón de cosas en ella, y sus derivados pueden volverse bastante difíciles de manejar, pero ahora tenemos una aproximación polinómica de D !

Haciendo un poco de cálculo, encontramos las siguientes dos derivadas Dal evaluar las derivadas de Di, como antes:

Derivado 2 de Di

Derivado 3 de Di

Al truncar y evaluar las derivadas, ahora podemos aproximarnos Dcomo un polinomio de tercer grado de la forma:

Forma aproximada de D

¿Dónde A, B, C, Destán simplemente los números reales?

Ahora esto podemos minimizarlo. Cuando tomamos una derivada y la establecemos igual a 0, terminaremos con una ecuación de la forma:

Aproximación de D '

Haciendo el cálculo y las sustituciones, se nos ocurren estas fórmulas para a, b, and c:

Valor de un

Valor de b

Valor de c

Ahora nuestro problema nos da 2 soluciones dadas por la fórmula cuadrática:

Valor de k

La fórmula completa para ksería una carga enorme de escribir, por lo que lo hacemos en pedazos aquí y en el código.

Como sabemos que cuanto más alto k siempre dará como resultado la distancia mínima de nuestro aproximado D(tengo una prueba realmente maravillosa de esto, que el margen de este documento es insuficiente para contener ...) ni siquiera tenemos que considerar el más pequeño de las soluciones.

Queda un último problema. Para fines de precisión, es necesario que comencemos con unk0 que esté al menos en el estadio de donde esperamos que esté la respuesta. Para este propósito, mi código elige la media geométrica de los valores y de cada casa.

Como a prueba de fallas, repetimos todo el problema nuevamente 9 veces, reemplazando k0conk cada iteración, para garantizar la precisión.

No he hecho los cálculos sobre cuántas iteraciones y cuántos derivados son realmente necesarios, pero he optado por errar por precaución hasta que pueda confirmar la precisión.

Si lo lograste conmigo, ¡muchas gracias! Espero que haya entendido, y si detecta algún error (de los cuales probablemente haya muchos, estoy muy cansado), ¡hágamelo saber!

BrainSteel
fuente
2
A mí, por mi parte, me encantaría ver la explicación de tus matemáticas.
DLosc
2
@DLosc Tu deseo es mi comando.
BrainSteel
44
Eso es realmente maravilloso. Pensé en probar el Método de Newton, pero no pensé en la serie Taylor.
DLosc
55
Desearía poder votar esto más.
Alex A.
@AlexA. Ojalá pudieras votarme más; D Dentro de un día más o menos, eliminaré la última referencia del teorema de Fermat y la reemplazaré con una prueba. Tan pronto como encuentre uno.
BrainSteel
13

TI-BASIC, 20

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

Toma información en la pantalla de inicio de su calculadora de la serie TI-83 u 84 de esta forma (puede escribir una 2:primera, que sería ignorada):

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

Si las casas están siempre a menos de mil millones de kilómetros del origen, E99 se puede reemplazar por E9 para un tamaño de 18 bytes.

Si hubiera un lenguaje de golf basado en Mathematica, podría ganar este desafío en 10-14 bytes.

lirtosiast
fuente
10

Mathematica, 42 bytes

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

Esta es una función anónima que toma una lista de pares como coordenadas de la casa y devuelve la coordenada y deseada.

Es una implementación bastante sencilla. Mapeamos Norm[#-{0,k}]&en cada coordenada de la casa (que calcula la distancia a un punto indeterminado {0,k}en el eje y) y los sumamos a todos Tr[...](para trazar, que es equivalente a las Totallistas 1-d). Luego usamos el conveniente Minimizepara encontrar el mínimo de esta suma en k. Esto da un resultado del formulario {distance, {k -> position}, por lo que necesitamos k/.Last@extraer el positionque estamos buscando.

Martin Ender
fuente
6

Pyth, 33 bytes

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

Esta es la solución de fuerza bruta: ordena todas las ubicaciones posibles del restaurante, con una resolución de 0,001 km, por su distancia total de las casas, luego selecciona la que tenga la menor distancia total. Toma las ubicaciones de la casa como una lista de 2 listas de entradas de carrozas en STDIN.

Demostración.

La resolución se puede establecer en cualquier lugar de 1e-2 km a 1e-10 km con la misma longitud de código, pero con ralentizaciones exponenciales en tiempo de ejecución.

Siento que esto podría jugarse un poco más, lo volveré a ver más tarde.

isaacg
fuente
2
Jajaja ¿Copiaste mi solución? ;-)
Jakube
@Jakube La coincidencia ^T3es especialmente impresionante.
isaacg
Realmente necesitamos un rango de flotación.
Maltysen
3

Pitón 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
dieter
fuente
3

R, 145 143 126

Sospecho que queda mucho espacio para jugar al golf. Prácticamente un método de fuerza bruta. Me gustaría encontrar una mejor manera de hacer esto. Pensé que los medios geométricos podrían ayudar, pero por desgracia no.

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

Prueba de funcionamiento

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

Como cuestión de interés, si solo hay dos casas a considerar, lo siguiente arrojará un resultado aceptable. Sin embargo, cae sobre tres. No puedo ir más lejos en este momento, pero pensé que algunos de los cerebros aquí podrían hacer algo con él.

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

MATLAB, 42

Si está bien tomar la entrada como

I=[5.7 3.2
    8.9 8.1]

entonces esta declaración

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

vuelve 5.113014445748538.

Robando descaradamente el método de Thomas Kwa, puedes reducirlo a 30 al menos:

I=[5.7+3.2i 8.9+8.1i];
fminunc(@(y)sum(abs(I-i*y)),0)
David
fuente
1
¿Se puede ampliar para trabajar con nnúmero de casa? Ya que es lo que pide la pregunta.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳
Sí, funciona con cualquier número de filas I.
David