Де мені поставити ресторан?


15

Ви власник ресторану. Ви відкриваєтесь у новому районі Картезії, де є лише одна головна дорога, відома як вісь y. Ви хочете розмістити ресторан таким чином, щоб ви мінімізували загальну відстань від вашого ресторану та кожного з будинків у цьому районі.

Вхід :

Вхід буде

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

де кожен будинок є координатою за формою x y. Кожна одиниця представляє один кілометр.

Ви можете взяти введення як рядок або надати функцію, яка приймає вхід у будь-якому форматі як аргументи.

Вихід : координата 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 (5.7, 3.2), а B на B (8.9, 8.1). Нехай точка розв’язку в (0, k) дорівнює C. Відбийте A над віссю y, щоб A 'склав (-5,7, 3.2). Відстань від A 'до C дорівнює відстані від A до C. Тому задачу можна звести до точки C такою, що A'C + CB мінімізується. Очевидно, це була б точка С, що лежить на прямій А'В.

Я не знаю, чи добре це узагальнить до 3 і більше балів.


Який показник використовується для функції відстані D? Евклідовий?
Рето Коради

1
Незважаючи на те, що існує лише одна головна дорога, чи вважаємо ми, що клієнт їде по прямій лінії від свого будинку до ресторану? Або вони спочатку прямують до осі y? (Або іншими словами, чи використовуємо ми евклідову чи манхеттенську відстань для D?)
трихоплакс

1
(Це можна розробити з прикладу, але непогано було б, щоб це було чітко зазначено.)
трихоплакс

@trichoplax Euclidean? Чи означає Євклідовий 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;}

Це далеко не досить, і це теж недовго. Я подумав, оскільки я не збираюсь вигравати змагання з тривалості, я можу спробувати виграти (теоретичний) конкурс на точність! Код, ймовірно, на порядок або на два швидше, ніж рішення грубої сили, і покладається на трохи математичної томфолерії.

Ми визначаємо функцію, 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досить погана ...

Похідне 1 Di

На жаль, навіть при n == 2встановленні цих похідних 0і вирішенні питання kстає дуже згубним. Нам потрібен більш надійний метод, навіть якщо він вимагає деякого наближення.

Введіть поліноми Тейлора.

Якщо ми знаємо значення, D(k0)як і всі Dпохідні 's у k0, ми можемо переписати Dяк Taylor Series:

Визначення серії Тейлор

Тепер ця формула містить в собі купу речей, і її похідні можуть стати досить громіздкими, але зараз ми маємо наближення полінома до D !

Зробивши трохи обчислення, ми знаходимо наступні два похідні D, оцінюючи похідні Di, як і раніше:

Похідне 2 Di

Похідне 3 Di

Урізаючи та оцінюючи похідні, ми можемо тепер Dвизначити поліном 3-го ступеня форми:

Орієнтовна форма D

Де A, B, C, D просто реальні числа.

Тепер це ми можемо мінімізувати. Коли ми візьмемо похідну і встановимо її рівній 0, ми закінчимо рівняння форми:

Апроксимація D '

Виконуючи обчислення та заміни, ми придумуємо такі формули для a, b, and c:

Значення a

Значення b

Значення c

Тепер наша проблема дає нам два рішення, задані квадратичною формулою:

Значення k

Вся формула для k було б важким тягарем для виписки, тому ми робимо це на шматочки тут і в коді.

Оскільки ми знаємо, що вище kзавжди призведе до мінімальної відстані нашої приблизної D(у мене є справді чудовий доказ цього, якого межа цього документу недостатній для вмісту ...), нам навіть не доведеться вважати меншим з рішення.

Залишається одна остаточна проблема. Для точності необхідно, щоб ми почали з аk0 що знаходиться принаймні в основній точці, де ми очікуємо відповіді. З цією метою мій код вибирає середнє геометричне значення y-значень кожного будинку.

Як несправність, ми повторюємо всю проблему ще раз 9 разів, замінюючи k0наk на кожній ітерації, щоб забезпечити точність.

Я не займався математикою щодо того, скільки ітерацій і скільки похідних справді необхідні, але я вирішив помилитися на стороні обережності, поки не зможу підтвердити точність.

Якщо ви пройшли це зі мною, дуже дякую! Сподіваюся, ви зрозуміли, і якщо ви помітите будь-які помилки (яких, мабуть, багато, я дуже втомився), будь ласка, повідомте мене!


2
Я, наприклад, хотів би бачити пояснення вашої математики.
DLosc

2
@DLosc Ваше бажання - це моя команда.
BrainSteel

4
Це справді дивовижно. Я думав пробувати метод Ньютона, але не думав про серію Тейлора.
DLosc

5
Я б хотів, щоб я міг підтримати це ще більше.
Олексій А.

@AlexA. Я б хотів, щоб ти міг схвалити мене ще більше; D Протягом дня я вилучу останню посилання теореми Ферма і заміню її доказом. Тільки що я знайду його.
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]

Якщо будинки завжди менше, ніж мільярд км від походження, E99 можна замінити на E9 розміром 18 байт.

Якщо була мова для гольфу на базі Mathematica, вона могла виграти це завдання в 10-14 байтів.


10

Математика, 42 байти

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

Це анонімна функція, яка приймає список пар як координати будинку і повертає потрібну координату y.

Це досить просто реалізація. Намалюємо Norm[#-{0,k}]&на кожну координату будинку (яка обчислює відстань до невизначеної точки {0,k}на осі y) і підсумовуємо їх усі Tr[...](для сліду, що еквівалентно Totalдля 1-d списків). Тоді ми використовуємо зручне, Minimizeщоб знайти мінімум цієї суми в k. Це дає результат форми {distance, {k -> position}, тому нам потрібно k/.Last@витягнути те, що positionми шукаємо.


6

Pyth, 33 байти

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

Це рішення грубої сили: воно впорядковує всі можливі місця ресторану з роздільною здатністю 0,001 км за загальною віддаленістю від будинків, а потім вибирає найменшу загальну відстань. Місця розташування будинків приймає як список із двох вхідних списків плавців на STDIN.

Демонстрація.

Дозвіл може бути встановлено десь від 1е-2 км до 1е-10 км при тій же довжині коду, але з експоненціальними уповільненнями в процесі виконання.

Я відчуваю, що це могло б стати ще одним гольфом, я перегляну його знову пізніше.


2
Лол! Ви скопіювали моє рішення? ;-)
Якубе

@Jakube Відповідність ^T3особливо вражає.
isaacg

Нам дійсно потрібен поплавковий діапазон.
Малтісен

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 .

Безсоромно вкравши метод Томаса Ква, ви могли звести його до 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.
Девід
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.