Tính điểm Fermat của tam giác


12

Điều này hơi giống với Trung tâm của một hình tam giác , nhưng với một điểm khác. Điểm Fermat là điểm P trong tam giác ABC sao cho giá trị của AP + BP + CP được giảm thiểu. Có hai trường hợp:

Nếu có một góc lớn hơn 120 độ, thì đỉnh đó là điểm fermat. Mặt khác, vẽ các tam giác đều trên mỗi cạnh của ABC. Nối đỉnh xa của mỗi tam giác đều với đỉnh đối diện của tam giác ABC. Làm điều này cho mỗi trong ba hình tam giác đều cho kết quả là một điểm giao nhau chung cho cả ba đường, đó là Điểm Fermat.

Nó sẽ chạy trong vòng 5 giây trên một máy hợp lý.

Đầu vào : Một bộ gồm 3 điểm, không nhất thiết phải là số nguyên. Điều này có thể được coi là một mảng lồng nhau, chuỗi, danh sách các bộ dữ liệu, vv (bất cứ điều gì phù hợp với ngôn ngữ của bạn).

Đầu ra : Một lần nữa tọa độ của điểm Fermat, tuy nhiên ngôn ngữ của bạn xử lý tốt nhất các điểm. Không chính xác điểm nổi sẽ không được tính vào bạn.

Các trường hợp thử nghiệm :

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

Đây là mã golf nên mã ngắn nhất sẽ thắng!


1
Bạn có thể thử tất cả các điểm theo gia số của độ chính xác của dấu phẩy động và chọn điểm tăng tối thiểu tổng khoảng cách không?
xnor

1
@xnor Nếu bạn có thể làm điều đó trong vòng 5 giây.
soktinpk

Lên đến bao nhiêu con số quan trọng phải được đầu ra chính xác? Ngoài ra, nó có ổn không nếu -0.0đầu ra thay cho một số 0.0s?
R. Kap

@R. Tôi muốn nói khoảng 5 hoặc 6 con số quan trọng. Không có quá nhiều lỗi làm tròn nên là một vấn đề. Đối với câu hỏi thứ hai, điều đó có vẻ tốt.
soktinpk

Câu trả lời:


3

Haskell, 346 291 285 byte

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)

Cùng một mã với một số giải thích

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

Các xét nghiệm:

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

Đầu ra:

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

Làm thế nào bạn đang đếm byte? £ và ¤ là ​​2 byte mỗi loại trong UTF-8 và tôi không biết trình biên dịch Haskell chấp nhận ISO-8859-1. (Tuy nhiên, bạn có rất nhiều toán tử ASCII 1 byte miễn phí, vì vậy điều này rất dễ khắc phục.)
Anders Kaseorg

Tôi đang đếm nó với biên tập viên của tôi, người thực sự đếm các ký tự. Tôi không biết rằng đây là 2 byte, nhưng dù sao, như bạn đã nói, tôi có thể thay thế nó bằng các toán tử 1 byte khác. Mã này biên dịch với GHC 7.8.3
Damien

GHC biên dịch mã của bạn khi được mã hóa dưới dạng UTF-8 với £¤là toán tử 2 byte, nhưng không được mã hóa dưới dạng ISO-8859-1 với £¤dưới dạng toán tử 1 byte. Các nhà khai thác có sẵn 1 byte trong UTF-8 là !, #, %, &, ?. Bạn nên thay thế các toán tử 2 byte hoặc điều chỉnh số byte của bạn.
Anders Kaseorg

2

Con trăn 475 448 440 byte

Bất kỳ trợ giúp để chơi gôn hơn nữa được đánh giá cao.

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

Ung dung:

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

Đầu vào:

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

Đầu ra:

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

2
from math import*là một sân golf khá phổ biến. Điều này cũng sẽ cho phép bạn sử dụng pithay vì mã hóa cứng (cùng độ dài cho 2*pi/3). Bạn cũng có thể thả rất nhiều khoảng trắng như : d=lambda x,y:(....
FryAmTheEggman

2

Python 3.5, 1019 1016 998 982 969 953 byte:

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]

Cực kỳ dài so với các câu trả lời khác, nhưng này, ít nhất nó hoạt động! Tôi không thể hạnh phúc hơn với kết quả mà tôi nhận được vì đây phải là một trong những thử thách khó khăn nhất tôi từng làm. Tôi rất vui vì nó thực sự hoạt động! : D Bây giờ, vào các ghi chú kỹ thuật hơn:

  • Hàm này nhận mỗi cặp theo thứ tự dưới dạng một danh sách hoặc một tuple. Ví dụ, H((1,1),(2,2),(1,2))sẽ làm việc, nhưng cũng sẽ như vậy H([1,1],[2,2],[1,2]).
  • Xuất ra tọa độ của các điểm trong danh sách các số nguyên hoặc dấu phẩy động tùy thuộc vào việc có tồn tại một góc lớn hơn hoặc bằng 120º hay không.
  • Điều này có thể đầu ra -0.0thay 0.0cho một số đầu vào. Ví dụ, đầu ra cho đầu vào [-1, -1], [1, -1], [0, 1][-0.0, -0.4226497308103744]. Tôi hy vọng điều này là ổn, mặc dù nếu không, tôi sẽ thay đổi nó, mặc dù nó sẽ khiến tôi tốn thêm một vài byte. Điều này là ổn, như được xác nhận bởi OP .
  • Nên lên chính xác để ít nhất 13để 14con số đáng kể.

Tôi sẽ cố gắng và chơi golf này nhiều hơn theo thời gian. Một lời giải thích, có thể rất dài, đến sớm.

Dùng thử trực tuyến! (Ý)


1

Toán học, 39 byte

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

Xây dựng phương trình dựa trên khoảng cách giữa các đỉnh và một điểm {x,y}. Sau đó, sử dụng NArgMinhàm để tìm mức tối thiểu toàn cầu cho phương trình đó, đó sẽ là Điểm Fermat theo định nghĩa.

Thí dụ


1
39 byte, khi câu trả lời ngắn nhất tiếp theo là 285 ...
Bálint
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.