ฉันควรใส่ร้านอาหารไว้ที่ไหน


15

คุณเป็นเจ้าของร้านอาหาร คุณกำลังเปิดในพื้นที่ใหม่ใน Cartesia ที่มีถนนสายหลักเพียงเส้นเดียวเท่านั้นที่รู้จักกันในชื่อแกน 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กิโลเมตร

นี่คือรหัสกอล์ฟ - รหัสที่สั้นที่สุดชนะ

ป.ล. ฉันยังสนใจในวิธีการแก้ปัญหาทางคณิตศาสตร์ที่ไม่ได้เป็นเพียงกำลังดุร้าย มันจะไม่ชนะ code golf แต่มันจะได้ upvotes นี่คือวิธีที่ฉันทำปัญหาตัวอย่าง:

ให้จุด 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 ดังนั้นปัญหาสามารถลดลงถึงจุด C เพื่อให้ A'C + CB ถูกย่อให้เล็กสุด เห็นได้ชัดว่านี่คือจุด C ที่อยู่บนเส้น A'B

ฉันไม่รู้ว่ามันจะพูดได้ดีถึง 3 คะแนนขึ้นไปหรือเปล่า


สิ่งที่ตัวชี้วัดที่ใช้สำหรับฟังก์ชั่นระยะทางD? ยุคลิด?
Reto Koradi

1
แม้ว่าจะมีถนนสายหลักเพียงเส้นทางเดียวเราคิดว่าลูกค้าเดินทางเป็นเส้นตรงจากบ้านไปร้านอาหารหรือไม่? หรือพวกเขาเดินทางไปยังแกน y โดยตรงหรือไม่? (หรือในคำอื่น ๆ เราจะใช้ Euclidean หรือระยะทางแมนฮัตตันเป็น D หรือเปล่า)
trichoplax

1
(ซึ่งสามารถทำงานได้จากตัวอย่าง แต่มันจะดีที่จะมีการระบุไว้อย่างชัดเจน)
trichoplax

@trichoplax Euclidean? แบบยุคลิดหมายความว่าsqrt(diffX^2 + diffY^2)อย่างไร? แล้วยุคลิด ฉันรู้ว่ามันไม่เหมาะกับสถานการณ์อย่างสมบูรณ์ แต่สมมติว่าลูกค้าเดินทางเป็นเส้นตรงจากบ้านของเขา / เธอ
soktinpk

5
การป้อนข้อมูลเป็นรายการของจำนวนเชิงซ้อนที่แสดงถึงตำแหน่งของบ้านบนระนาบเชิงซ้อนที่ยอมรับได้หรือไม่
lirtosiast

คำตอบ:


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

มันค่อนข้างไกลและก็ไม่สั้นด้วยเช่นกัน ฉันคิดว่าเนื่องจากฉันจะไม่ชนะการแข่งขันที่มีความยาวฉันสามารถพยายามที่จะชนะการแข่งขันที่แม่นยำ (ตามทฤษฎี)! รหัสอาจเป็นลำดับความสำคัญหรือสองเร็วกว่าโซลูชัน bruteforce และอาศัยบิตของ tomfoolery ทางคณิตศาสตร์

เรากำหนดฟังก์ชั่นg(N,S)ซึ่งจะเป็น input จำนวนบ้านที่และอาร์เรย์ของบ้านNS[][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กลายเป็นหายนะอย่างรวดเร็ว เราต้องการวิธีที่แข็งแกร่งกว่าแม้ว่าจะต้องใช้การประมาณ

ป้อนชื่อพหุนาม Taylor

ถ้าเรารู้คุณค่าของอนุพันธ์D(k0)เช่นเดียวกับDที่k0เราสามารถเขียนใหม่ได้Dเป็นเทย์เลอร์ซีรีส์:

นิยามโดย Taylor Series

ทีนี้สูตรนี้มีหลายอย่างอยู่ในนั้นและอนุพันธ์ของมันค่อนข้างเทอะทะแต่ตอนนี้เรามีพหุนามประมาณ D !

ด้วยแคลคูลัสนิดหน่อยเราจะพบอนุพันธ์สองตัวถัดไปDโดยการประเมินอนุพันธ์ของDiเช่นเดียวกับก่อนหน้านี้:

อนุพันธ์ 2 ของ Di

อนุพันธ์ 3 ของ Di

โดยการตัดและประเมินผลอนุพันธ์ตอนนี้เราอาจประมาณDว่าพหุนามระดับ 3 ของแบบฟอร์ม:

รูปแบบโดยประมาณของ D

ในกรณีที่A, B, C, Dเป็นตัวเลขก็จริง

ตอนนี้เราสามารถลด เมื่อเราหาอนุพันธ์และตั้งค่าเป็น 0 เราจะจบลงด้วยสมการของรูปแบบ:

ประมาณ D '

การทำแคลคูลัสและการแทนที่เราได้รับสูตรเหล่านี้เพื่อa, b, and c:

ค่าของ

ค่าของ b

ค่าของค

ตอนนี้ปัญหาของเราให้ 2 วิธีแก้ปัญหาโดยสูตรสมการกำลังสอง:

ค่าของ k

สูตรทั้งหมดสำหรับ kจะเป็นภาระอันยิ่งใหญ่ในการเขียนดังนั้นเราจึงทำมันเป็นชิ้น ๆ ที่นี่และในรหัส

เนื่องจากเรารู้ว่ายิ่งสูงขึ้นkจะส่งผลให้ระยะทางต่ำสุดโดยประมาณของเราD (ฉันมีหลักฐานอันน่าอัศจรรย์นี้ซึ่งขอบของบทความนี้ไม่เพียงพอที่จะมี ... ) เราไม่จำเป็นต้องพิจารณาขนาดเล็ก การแก้ปัญหา

ปัญหาสุดท้ายยังคงอยู่ เพื่อความถูกต้องเราจำเป็นต้องเริ่มต้นด้วยk0อย่างน้อยใน ballpark ที่เราคาดหวังคำตอบ เพื่อจุดประสงค์นี้รหัสของฉันเลือกค่าเฉลี่ยเรขาคณิตของค่า y ของบ้านทุกหลัง

ในฐานะที่ไม่ปลอดภัยเราจะทำซ้ำปัญหาทั้งหมดอีกครั้ง 9 ครั้งแทน k0ด้วยkในทุกย้ำเพื่อความถูกต้อง

ฉันยังไม่ได้ทำคณิตศาสตร์เกี่ยวกับจำนวนการวนซ้ำและจำนวนอนุพันธ์ที่จำเป็นจริง ๆ แต่ฉันเลือกที่จะทำผิดโดยใช้ความระมัดระวังจนกระทั่งฉันสามารถยืนยันความถูกต้องได้

ถ้าคุณทำผ่านสิ่งนั้นกับฉันขอบคุณมาก! ฉันหวังว่าคุณจะเข้าใจและหากคุณพบข้อผิดพลาดใด ๆ (ซึ่งมีโอกาสมากที่ฉันจะเหนื่อยมาก) โปรดแจ้งให้เราทราบ!


2
ฉันคนหนึ่งชอบที่จะเห็นคำอธิบายของคณิตศาสตร์ของคุณ
DLosc

2
@DLosc ความปรารถนาของคุณคือคำสั่งของฉัน
BrainSteel

4
นั่นเป็นเรื่องมหัศจรรย์อย่างแท้จริง ฉันลองใช้วิธีของนิวตัน แต่ก็ไม่ได้คิดถึงซีรีย์ของเทย์เลอร์
DLosc

5
ฉันหวังว่าฉันจะโหวตได้มากกว่านี้
Alex A.

@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

Mathematica ขนาด 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 กม. โดยรวมระยะทางจากบ้านของพวกเขาแล้วเลือกหนึ่งที่มีระยะทางรวมน้อยที่สุด ใช้ที่ตั้งของบ้านเป็นรายการของ 2 รายการของการลอยบน STDIN

สาธิต.

ความละเอียดสามารถตั้งค่าได้ทุกที่ตั้งแต่ 1e-2 km ถึง 1e-10 km ที่ความยาวโค้ดเท่ากัน แต่ด้วยการชะลอตัวแบบเอ็กซ์โปเนนเชียลในการรันไทม์

ฉันรู้สึกว่าสิ่งนี้สามารถเล่นกอล์ฟได้มากกว่านี้ฉันจะดูอีกครั้งในภายหลัง


2
ฮ่า ๆ! คุณคัดลอกโซลูชันของฉันหรือไม่ ;-)
Jakube

@Jakube การจับคู่^T3นั้นน่าประทับใจเป็นพิเศษ
isaacg

เราจำเป็นต้องมีช่วงลอย
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

มีห้องเล่นกอล์ฟเหลืออยู่ในห้องนี้ฉันสงสัย ค่อนข้างเป็นวิธีบังคับเดรัจฉาน ฉันต้องการหาวิธีที่ดีกว่าในการทำเช่นนี้ ฉันว่าเรขาคณิตหมายถึงอาจช่วยได้ แต่ก็ไม่ใช่

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ผลตอบแทน

การขโมยวิธีของ Thomas Kwa อย่างไร้ยางอายคุณสามารถทำให้มันลดลงเหลือ 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ของแถวใน
David
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.