개정 1 : 루비, 354 바이트
blutorange 덕분에 더 많은 골프.
->a{t=s=Math::PI/18E4
d=r=c=0
a=a.map{|e|e-a[0]}
0.upto(36E4){|i|b=a.map{|e|(e/Complex.polar(1,i*s)).rect}.transpose
m,n=b
if n.min>=f=0
l=[m.max-x=m.min,n.max].max
a.each_index{|j|f+=((l-w=n[j])*(x+l-v=m[j])*(x-v)*w)**2}
(1E-9>q=f/l**8)&&(c>0&&(i-d)%9E4%89E3>1E3?c=9E9:0;c+=1;d=i)
q<t&&(r=i)&&t=q;end}
c<101&&a[1]?c<1?'impossible':r%9E4/1.0E3:'unknown'}
루비, 392 바이트
->(a){
s=Math::PI/18E4
t=1
d=r=c=0
a=a.map{|e|e-a[0]}
(0..36E4).each{|i|
b=a.map{|e|(e/Complex.polar(1,i*s)).rect}.transpose
m=b[0]
n=b[1]
x=m.min
if n.min>=0
l=[m.max-x,n.max].max
f=0
a.each_index{|j|f+=((l-n[j])*(x+l-m[j])*(x-m[j])*n[j])**2}
q=f/l**8
if q<1E-9
c>0&&(i-d)%9E4%89E3>1E3?(c=9E9):0
c+=1
d=i
end
if q<t
r=i
t=q
end
end
}
c>100||a.size<2?'unknown':c<1? 'impossible':r%9E4/1.0E3
}
알고리즘은 다음과 같습니다.
-임의의 점 (첫 번째 점)을 선택하고 원점으로 이동합니다 (목록의 모든 점에서이 점의 좌표를 뺍니다.)
-원점에 대한 정사각형의 모든 회전을 360도를 통해 0.001 도씩 증가시켜보십시오.
-주어진 회전에서 모든 점이 y 축 위에 있으면 가장 낮은 점과 가장 왼쪽 점을 포함하여 모든 점 주위에 가능한 가장 작은 사각형을 그립니다.
-모든 점이 가장자리에 있는지 확인하십시오. 이것은 각 점을 취하고 모든 모서리에서 제곱 거리를 찾아 곱하는 부드러운 계산으로 수행됩니다. 이것은 예 / 아니오 답변이 아닌 적합합니다. 이 제품을 sidelength ^ 8 (으)로 나눈 값이 1E-9보다 작 으면 해가 발견되는 것으로 해석됩니다. 실제로 이것은 허용 오차 미만입니다.
-가장 잘 맞는 모드는 90도이며 올바른 각도로보고됩니다.
현재이 코드는 100 개가 넘는 솔루션이 발견되면 모호한 값을 반환합니다 (0.001도 분해능, 0.1도 허용 오차).
테스트 프로그램에서 최초의 완전 작동 기능
속도를 합리적으로 만들기 위해 필요한 해상도의 1/10로 해상도를 남겼습니다. 가장 마지막 테스트 사례에서 0.01 degress 오류가 있습니다.
g=->(a){
s=Math::PI/18000
t=1
d=r=-1
c=0
a=a.map{|e| e-a[0]}
(0..36000).each{|i|
b=a.map{|e|(e/Complex.polar(1,i*s)).rect}.transpose
m=b[0]
n=b[1]
x=m.min
if n.min>=0
l=[m.max-x,n.max].max
f=0
a.each_index{|j|f+=((l-n[j])*(x+l-m[j])*(x-m[j])*n[j])**2}
q=f/l**8
if q<1E-9
j=(i-d)%9000
c>0&&j>100&&j<8900?(c=9E9):0
c+=1
d=i
end
if q<t
r=i
t=q
end
end
}
print "t=",t," r=",r," c=",c," d=",d,"\n"
p c>100||a.size<2?'unknown':c<1? 'impossible':r%9000/100.0
}
#ambiguous
#g.call([Complex(0,0)])
#g.call([Complex(0,0),Complex(1,0)])
#g.call([Complex(0,0),Complex(1,0),Complex(0,1)])
#g.call([Complex(0,0),Complex(1,0),Complex(0,1),Complex(1,1)])
#g.call([Complex(0,1),Complex(0,2),Complex(1,0),Complex(1,3),Complex(2,0),Complex(2,3),Complex(3,1),Complex(3,2)])
#impossible
#g.call([Complex(0,0),Complex(1,0),Complex(2,0),Complex(3,1),Complex(4,2)])
#g.call([Complex(0,0),Complex(1,0),Complex(2,0),Complex(1,1)])
#g.call([Complex(0,1),Complex(0,2),Complex(1,0),Complex(1,3),Complex(2,0),Complex(2,3),Complex(3,1),Complex(3,2),Complex(2,2)])
#g.call([Complex(2,0),Complex(0,1),Complex(2,2),Complex(0,3)])
#g.call([Complex(0,0),Complex(2,1),Complex(0,2),Complex(2,2),Complex(-1,1)])
#possible
g.call([Complex(0,0),Complex(1,0),Complex(2,0)])
g.call([Complex(0,0),Complex(0.3,0.3),Complex(0.6,0.6)]) #(should return 45)
g.call([Complex(0,0),Complex(0.1,0.2),Complex(0.2,0.4)]) #(should return appx 63.435 (the real value is arctan(2)))
g.call([Complex(0,0),Complex(0,1),Complex(2,1),Complex(2,2)])
g.call([Complex(0,1),Complex(0,2),Complex(1,0),Complex(1,4),Complex(2,0),Complex(2,4),Complex(4,1),Complex(4,3)])
테스트 프로그램에서 사양을 준수하는 해상도의 골프 버전은 통화 당 약 1 분이 걸립니다.
마지막 테스트 사례에서 여전히 0.001 도의 성가신 오류가 있습니다. 해상도를 높이면 제거 할 수 있습니다.
g=->(a){ #take an array of complex numbers as input
s=Math::PI/18E4 #step size PI/180000
t=1 #best fit found so far
d=r=c=0 #angles of (d) last valid result, (r) best fit; c= hit counter
a=a.map{|e|e-a[0]} #move shape so that first point coincides with origin
(0..36E4).each{|i| #0..360000
b=a.map{|e|(e/Complex.polar(1,i*s)).rect}.transpose #rotate each element by dividing by unit vector of angle i*s, convert to array...
m=b[0] #...transpose array [[x1,y1]..[xn,yn]] to [[x1..xn],[y1..yn]]...
n=b[1] #...and assign to variables m and n
x=m.min #find leftmost point
if n.min>=0 #if all points are above x axis
l=[m.max-x,n.max].max #find the sidelength of smallest square in which they will fit
f=0 #f= accumulator for errors. For each point
a.each_index{|j|f+=((l-n[j])*(x+l-m[j])*(x-m[j])*n[j])**2} #...add to f the product of the squared distances from each side of the smallest square containing all points
q=f/l**8 #q= f normalized with respect to the sidelength.
if q<1E-9 #consider a hit if <1E-9
c>0&&(i-d)%9E4%89E3>1E3?(c=9E9):0 #if at least one point is already found, and the difference between this hit and the last exceeds+/-1 deg (mod 90), set c to a high value
c+=1 #increment hit count by 1 (this catches infinitely varible cases)
d=i #store the current hit in d
end
if q<t #if current fit is better than previous one
r=i #store the new angle
t=q #and revise t to the new best fit.
end
end
}
c>100||a.size<2?'unknown':c<1? 'impossible':r%9E4/1.0E3 #calculate and return value, taking special care of case where single point given.
}
#ambiguous
puts g.call([Complex(0,0)])
puts g.call([Complex(0,0),Complex(1,0)])
puts g.call([Complex(0,0),Complex(1,0),Complex(0,1)])
puts g.call([Complex(0,0),Complex(1,0),Complex(0,1),Complex(1,1)])
puts g.call([Complex(0,1),Complex(0,2),Complex(1,0),Complex(1,3),Complex(2,0),Complex(2,3),Complex(3,1),Complex(3,2)])
#impossible
puts g.call([Complex(0,0),Complex(1,0),Complex(2,0),Complex(3,1),Complex(4,2)])
puts g.call([Complex(0,0),Complex(1,0),Complex(2,0),Complex(1,1)])
puts g.call([Complex(0,1),Complex(0,2),Complex(1,0),Complex(1,3),Complex(2,0),Complex(2,3),Complex(3,1),Complex(3,2),Complex(2,2)])
puts g.call([Complex(2,0),Complex(0,1),Complex(2,2),Complex(0,3)])
puts g.call([Complex(0,0),Complex(2,1),Complex(0,2),Complex(2,2),Complex(-1,1)])
#possible
puts g.call([Complex(0,0),Complex(1,0),Complex(2,0)])
puts g.call([Complex(0,0),Complex(0.3,0.3),Complex(0.6,0.6)]) #(should return 45)
puts g.call([Complex(0,0),Complex(0.1,0.2),Complex(0.2,0.4)]) #(should return appx 63.435 (the real value is arctan(2)))
puts g.call([Complex(0,0),Complex(0,1),Complex(2,1),Complex(2,2)])
puts g.call([Complex(0,1),Complex(0,2),Complex(1,0),Complex(1,4),Complex(2,0),Complex(2,4),Complex(4,1),Complex(4,3)])
약 30 % 더 많은 코드에 대해이 알고리즘은 빠르게 작동하도록 조정할 수 있습니다. 유한 한 수의 솔루션을 사용하는 경우 모서리 중 하나가 큐브를 따라 평평하게 놓여 있기 때문에 실제로 시도해야 할 모든 각도는 각 정점 쌍에 해당합니다. 또한 무한히 많은 솔루션이 없는지 확인하기 위해 약간의 흔들림이 필요합니다.