คำนวณจุดแฟร์มาต์ของรูปสามเหลี่ยม


13

นี่ค่อนข้างคล้ายกับศูนย์กลางของรูปสามเหลี่ยมแต่มีจุดที่แตกต่างกัน แฟร์มาต์พอยต์เป็นจุด P ในรูปสามเหลี่ยม ABC ดังกล่าวว่าค่าของ AP + BP + ซีพีจะลดลง มีสองกรณี:

หากมีมุมที่มากกว่า 120 องศาจุดยอดนั่นคือจุดแฟร์มาต์ มิฉะนั้นวาดรูปสามเหลี่ยมด้านเท่าที่ด้านข้างของ ABC เชื่อมต่อจุดสุดยอดของรูปสามเหลี่ยมด้านเท่าแต่ละด้านกับจุดยอดตรงข้ามของรูปสามเหลี่ยม ABC การทำเช่นนี้สำหรับสามเหลี่ยมมุมฉากแต่ละรูปสามรูปนั้นส่งผลให้เกิดจุดร่วมจุดเดียวของจุดตัดทั้งสามเส้นซึ่งก็คือจุดแฟร์มาต์

ควรรันภายใน 5 วินาทีบนเครื่องที่เหมาะสม

อินพุต : ชุด 3 คะแนนไม่จำเป็นต้องเป็นจำนวนเต็ม สิ่งนี้สามารถนำมาเป็นอาร์เรย์สตริงรายการของสิ่งอันดับเป็นต้น (สิ่งใดก็ตามที่เหมาะสมกับภาษาของคุณ)

เอาท์พุท : พิกัดของจุดแฟร์มาต์อีกครั้งอย่างไรก็ตามภาษาของคุณจัดการกับจุดที่ดีที่สุด ความไม่ถูกต้องของคะแนนลอยตัวจะไม่ถูกนับรวมกับคุณ

กรณีทดสอบ :

[[1, 1], [2, 2], [1, 2]] --> [1.2113248654051871, 1.788675134594813]
[[-1, -1], [-2, -1], [0, 0]] --> [-1, -1]
[[-1, -1], [1, -1], [0, 1]] --> [0, -0.42264973081037427]
[[0, 0], [0.5, 0.8660254037844386], [-5, 0]] --> [0, 0]
[[0, 0], [0, -5], [-0.8660254037844386, 0.5]] --> [0, 0]

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


1
ตกลงหรือไม่ที่จะลองใช้คะแนนทั้งหมดในการเพิ่มความแม่นยำของจุดลอยตัวและเลือกจุดที่จะลดระยะทางทั้งหมด
xnor

1
@xnor หากคุณสามารถทำได้ภายใน 5 วินาที
soktinpk

ผลลัพธ์ที่ได้จะต้องมีความแม่นยำถึงกี่ตัว? นอกจากนี้มันจะโอเคไหมถ้า-0.0เอาท์พุทแทนที่บางตัว0.0?
R. Kap

@R Kap ฉันพูดถึงตัวเลขที่มีนัยสำคัญประมาณ 5 หรือ 6 ตัว มีไม่มากนักที่ข้อผิดพลาดในการปัดเศษควรเป็นปัญหา สำหรับคำถามที่สองดูเหมือนว่าใช้ได้
soktinpk

คำตอบ:


3

Haskell, 346 291 285 ไบต์

infixl 5£
z=zipWith
(?)=z(-)
t[a,b]=[-b,a]
a¤b=sum$z(*)a b
a%b=t a¤b
r a b c=[c%b/a%b,c%a/a%b]
x£y=2*x¤y<= -sqrt(x¤x*y¤y)
f[a,b,c]|a?b£c?b=b|a?c£b?c=c|b?a£c?a=a|[n,m,p,o]<-c?k a b c++a?k b c a=r[m,o][n,p][c%[n,m],a%[p,o]]
k a b c=map(/2)$z(+)a b?map(signum((b?a)%(c?a))*sqrt 3*)(t$b?a)

รหัสเดียวกันกับคำอธิบายบางอย่าง

infixl 5£
z=zipWith

-- operator ? : difference of two vectors
(?)=z(-)            

-- function t : rotate a vector by +90 degrees
t[a,b]=[-b,a]       

-- operator ¤ : scalar product of two vectors ( a¤b = a0 * b0 + a1 * b1 )
a¤b=sum$z(*)a b     

-- operator % : "cross product" of two vectors ( a%b = a0 * b1 - a1 * b0 )
--      this returns actually the z coordinate of the 3d cross vector
--      other coordinates are nul since a and b are in the xy plan
a%b=t a¤b

-- function r : solves the system of two linear equations with two variables x0,x1 :
--      a0*x0 - b0*x1 = c0
--      a1*x0 - b1*x1 = c1
r a b c=[c%b/a%b,c%a/a%b]

-- operator £ : returns true if the angle between two vectors is >= 120 degrees
--      x¤y = ||x|| * ||y|| * cos(xyAngle)
--      so xyAngle>=120° is equivalent to : x¤y / (||x|| * ||y||) <= -0.5
x£y=2*x¤y<= -sqrt(x¤x*y¤y)

-- function k : takes 3 points A B C of a triangle and constructs the point C' 
--              of the equilateral triangle ABC' which is opposite to C:
--              C' = (A+B)/2 - ((+/-) sqrt(3)/2 * t(AB))
--
--      the sign +/- is given by the sign of the cross vector of AB an AC ((b?a)%(c?a))
--      which is >0 if the angle between AB and AC is positive
--      and <0 otherwise.
k a b c=map(/2)$z(+)a b?map(signum((b?a)%(c?a))*sqrt 3*)(t$b?a)

-- function f : returns the fermat point of a triangle
f[a,b,c]
    |a?b£c?b=b  -- return B if angle ABC >= 120°
    |a?c£b?c=c  -- return C if angle BCA >= 120°
    |b?a£c?a=a  -- return A if angle CAB >= 120°
    |[n,m,p,o]<-c?k a b c++a?k b c a= -- calculate the two segments C'C and A'A
        r[m,o][n,p][c%[n,m],a%[p,o]]  -- return their intersection

แบบทดสอบ:

main = do 
    print $ f [[1, 1], [2, 2], [1, 2]]
    print $ f [[-1, -1], [-2, -1], [0, 0]]
    print $ f [[-1, -1], [1, -1], [0, 1]]
    print $ f [[0, 0], [0.5, 0.8660254037844386], [-5, 0]]
    print $ f [[0, 0], [0, -5], [-0.8660254037844386, 0.5]]

เอาท์พุท:

[1.2113248654051871,1.7886751345948126]
[-1.0,-1.0]
[0.0,-0.42264973081037427]
[0.0,0.0]
[0.0,0.0]

คุณนับจำนวนไบต์เป็นอย่างไร £และ¤คือ 2 ไบต์ใน UTF-8 และฉันไม่รู้คอมไพเลอร์ Haskell ที่ยอมรับ ISO-8859-1 (คุณมีโอเปอเรเตอร์ ASCII ขนาด 1 ไบต์ฟรีดังนั้นนี่จึงเป็นเรื่องง่ายที่จะแก้ไข)
Anders Kaseorg

ฉันกำลังนับมันด้วยเครื่องมือแก้ไขซึ่งนับจำนวนตัวอักษรจริงๆ ฉันไม่รู้ว่ามันมีขนาด 2 ไบต์ แต่อย่างที่คุณบอกว่าฉันสามารถแทนที่มันด้วยตัวดำเนินการ 1 ไบต์อื่น รหัสนี้รวมกับ GHC 7.8.3
ดาเมียน

GHC รวบรวมรหัสของคุณเมื่อเข้ารหัสเป็น UTF-8 £และ¤เป็นผู้ประกอบการ 2 ไบต์ แต่ไม่เมื่อเข้ารหัสเป็น ISO-8859-1 ด้วย£และ¤เป็นผู้ประกอบการ 1 ไบต์ ที่มีผู้ประกอบการ 1 ไบต์ใน UTF-8 !, #, %, ,& ?คุณควรแทนที่โอเปอเรเตอร์ 2 ไบต์หรือปรับจำนวนไบต์ของคุณ
Anders Kaseorg

2

งูหลาม 475 448 440 ไบต์

ความช่วยเหลือใด ๆ ในการเล่นกอล์ฟต่อไปคือความนิยม

from math import *
d=lambda x,y:((x[0]-y[0])**2+(x[1]-y[1])**2)**0.5
s=lambda A,B,C:(d(B,C), d(C,A), d(A,B))
j=lambda a,b,c:acos((b*b+c*c-a*a)/(2*b*c))
t=lambda a,b,c:1/cos(j(a,b,c)-pi/6)
b=lambda A,B,C,p,q,r:[(p*A[i]+q*B[i]+r*C[i])/(p+q+r) for i in [0,1]] 
f=lambda A,B,C:A if j(*s(A,B,C)) >= 2*pi/3 else B if j(*s(B,C,A)) >= 2*pi/3 else C if j(*s(C,A,B)) >= 2*pi/3 else b(A,B,C,d(B,C)*t(*s(A,B,C)),d(C,A)*t(*s(B,C,A)),d(A,B)*t(*s(C,A,B)))

Ungolfed:

from math import *
#distance between two points
d = lambda x,y: ((x[0]-y[0])**2+(x[1]-y[1])**2)**0.5

#given the points, returns the sides 
s = lambda A,B,C : (d(B,C), d(C,A), d(A,B))

#given the sides, returns the angle
j = lambda a,b,c : acos((b*b+c*c-a*a)/(2*b*c))

#given the sides, returns secant of that angle
t = lambda a,b,c: 1/cos(j(a,b,c)-pi/6)

#given the sides and the Trilinear co-ordinates, returns the Cartesian co-ordinates
b = lambda A,B,C,p,q,r: [(p*A[i]+q*B[i]+r*C[i])/(p+q+r) for i in [0,1]] 

#this one checks if any of the angle is >= 2π/3 returns that point else computes the point
f = lambda A,B,C: A if j(*s(A,B,C)) >= 2*pi/3 else B if j(*s(B,C,A)) >= 2*pi/3 else C if j(*s(C,A,B)) >= 2*pi/3 else b(A,B,C,d(B,C)*t(*s(A,B,C)),d(C,A)*t(*s(B,C,A)),d(A,B)*t(*s(C,A,B)))

การป้อนข้อมูล:

print('{}'.format(f([1, 1], [2, 2], [1, 2])))
print('{}'.format(f([-1, -1], [-2, -1], [0, 0])))
print('{}'.format(f([-1, -1], [1, -1], [0, 1])))
print('{}'.format(f([0, 0], [0.5, 0.8660254037844386], [-5, 0])))
print('{}'.format(f([0, 0], [0, -5], [-0.8660254037844386, 0.5])))

เอาท์พุท:

[1.2113248652983113, 1.7886751347016887]
[-1, -1]
[0.0, -0.42264973086764884]
[0, 0]
[0, 0]

2
from math import*เป็นสนามกอล์ฟที่ค่อนข้างธรรมดา สิ่งนี้จะช่วยให้คุณใช้piแทนการเข้ารหัสอย่างหนัก (ความยาวเท่ากัน2*pi/3) d=lambda x,y:(...นอกจากนี้คุณยังสามารถวางจำนวนมากของช่องว่างเช่น:
FryAmTheEggman

2

Python 3.5, 1019 1016 998 982 969 953 ไบต์:

from math import*
def H(z,a,b):c=complex;T=lambda A,B:abs(c(*A)-c(*B));d=T(z,a);e=T(z,b);f=T(a,b);g=[d,e,f];h=max(g);g.remove(h);i=acos((sum(i*i for i in g)-(h*h))/(2*g[0]*g[-1]));_=[[z,a],[z,b],[a,b]];j,s,t=cos,sin,atan;N=[[b,a]for a,b in zip([b,a,z],[max(i,key=i.get)if i!=''else''for i in[{(g[0]+(h*j(t(l))),g[1]+(h*s(t(l)))):T(k,(g[0]+(h*j(t(l))),g[1]+(h*s(t(l))))),(g[0]-(h*j(t(l))),g[1]-(h*s(t(l)))):T(k,(g[0]-(h*j(t(l))),g[1]-(h*s(t(l)))))}if l else{(g[0]+h,g[1]):T(k,(g[0]+h,g[1])),(g[0]-h,g[1]):T(k,(g[0]-h,g[1]))}if l==0else''for g,h,l,k in zip([((a[0]+b[0])/2,(a[1]+b[1])/2)for a,b in _],[(3**0.5)*(i/2)for i in[d,e,f]],[-1/p if p else''if p==0else 0for p in[((a[1]-b[1])/(a[0]-b[0]))if a[0]-b[0]else''for a,b in _]],[b,a,z])]])if b!=''];I=N[0][0][1];J=N[0][0][0];K=N[1][0][1];G=N[1][0][0];A=(N[0][1][1]-I)/(N[0][1][0]-J);B=I-(A*J);C=(K-N[1][1][1])/(G-N[1][1][0]);D=K-(C*G);X=(D-B)/(A-C);Y=(A*X)+B;return[[X,Y],[[a,b][h==d],z][h==f]][i>2.0943]

ไม่นานนักเมื่อเทียบกับคำตอบอื่น ๆ แต่อย่างน้อยมันก็ใช้ได้! ฉันไม่สามารถมีความสุขกับผลลัพธ์ที่ได้รับเนื่องจากนี่จะเป็นหนึ่งในความท้าทายที่ยากที่สุดที่ฉันเคยทำ ฉันมีความสุขมากที่ใช้งานได้จริง! : D ตอนนี้ไปยังบันทึกทางเทคนิคเพิ่มเติม:

  • ฟังก์ชั่นนี้ใช้เวลาสั่งซื้อแต่ละคู่ในรายการหรือทูเปิล ตัวอย่างเช่นH((1,1),(2,2),(1,2))จะใช้งานได้ แต่จะทำH([1,1],[2,2],[1,2])เช่นนั้น
  • เอาต์พุตพิกัดของจุดในรายการจำนวนเต็มหรือจุดลอยตัวขึ้นอยู่กับว่ามีมุมใดมุมหนึ่งมากกว่าหรือเท่ากับ 120 to อยู่หรือไม่
  • นี้การส่งออกเดือนพฤษภาคม-0.0ในสถานที่ของ0.0ปัจจัยการผลิตบางส่วน ยกตัวอย่างเช่นการส่งออกสำหรับการป้อนข้อมูลที่เป็น[-1, -1], [1, -1], [0, 1] ฉันหวังว่ามันจะโอเคแม้ว่ามันจะไม่เป็นเช่นนั้นฉันก็จะเปลี่ยนมัน นี่คือโอเคเช่นการยืนยันจาก OP[-0.0, -0.4226497308103744]
  • ควรมีความแม่นยำ13จนถึง14ตัวเลขที่มีนัยสำคัญอย่างน้อยที่สุด

ฉันจะพยายามเล่นกอล์ฟมากกว่านี้ตลอดเวลา คำอธิบายอาจจะนานมากเร็ว ๆ นี้

ลองออนไลน์! (Ideone)


1

Mathematica ขนาด 39 ไบต์

Sum[Norm[p-{x,y}],{p,#}]~NArgMin~{x,y}&

{x,y}สร้างสมการขึ้นอยู่กับระยะทางระหว่างจุดและจุด จากนั้นใช้NArgMinฟังก์ชันเพื่อค้นหาค่าต่ำสุดทั่วโลกสำหรับสมการนั้นซึ่งจะเป็นจุดแฟร์มาต์ตามคำจำกัดความ

ตัวอย่าง


1
39 ไบต์เมื่อคำตอบที่สั้นที่สุดถัดไปคือ 285 ...
Bálint
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.