Rev 1: Ruby, 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
}
อัลกอริทึมมีดังนี้:
- เลือกจุดโดยพลการ (จุดแรก) และย้ายไปยังจุดกำเนิด (ลบพิกัดของจุดนี้จากจุดทั้งหมดในรายการ)
- ลองการหมุนทั้งหมดของสแควร์เกี่ยวกับจุดกำเนิดในการเพิ่มขึ้น 0.001 องศาผ่าน 360 องศา
- สำหรับการหมุนที่กำหนดหากทุกจุดอยู่เหนือแกน y ให้วาดสี่เหลี่ยมจัตุรัสที่เล็กที่สุดเท่าที่เป็นไปได้รอบจุดทั้งหมดโดยรวมจุดต่ำสุดและซ้ายสุดไว้ด้วย
- ตรวจสอบว่าทุกจุดอยู่บนขอบ สิ่งนี้ทำด้วยการคำนวณแบบนุ่มนวลที่แต่ละจุดหาระยะทางยกกำลังสองจากขอบทั้งหมดแล้วคูณเข้าด้วยกัน สิ่งนี้ให้แบบที่ดีมากกว่าคำตอบใช่ / ไม่ใช่ ถูกตีความว่าพบวิธีแก้ปัญหาหากผลิตภัณฑ์นี้หารด้วย sidelength ^ 8 น้อยกว่า 1E-9 ในทางปฏิบัติมันน้อยกว่าระดับของความอดทน
- แบบที่ดีที่สุดถูกนำ mod 90 องศาและรายงานว่าเป็นมุมที่ถูกต้อง
ในปัจจุบันโค้ดส่งคืนค่าที่ไม่ชัดเจนหากพบโซลูชันมากกว่า 100 รายการ (ที่ความละเอียด 0.001 องศานั่นคือค่าเผื่อ 0.1 องศา)
ฟังก์ชั่นการทำงานอย่างเต็มที่ครั้งแรกในโปรแกรมทดสอบ
ฉันออกความละเอียดไว้ที่ 1 / 10th ของความละเอียดที่กำหนดเพื่อให้ความเร็วเหมาะสม มีข้อผิดพลาด 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)])
เวอร์ชัน golfed ความละเอียดที่สอดคล้องกับข้อมูลจำเพาะใช้เวลาประมาณหนึ่งนาทีต่อการโทรในโปรแกรมทดสอบ
ยังคงมีข้อผิดพลาดที่น่ารำคาญของ 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% อัลกอริทึมนี้สามารถปรับให้ทำงานได้อย่างรวดเร็ว: เห็นได้ชัดว่าในกรณีที่มีจำนวน จำกัด ของการแก้ปัญหาขอบด้านหนึ่งแบนราบตลอดแนวลูกบาศก์ลูกบาศก์ดังนั้นสิ่งที่เราต้องลองคือมุมเหล่านั้น ที่สอดคล้องกับแต่ละจุดยอด นอกจากนี้ยังจำเป็นต้องทำการกระดิกเล็กน้อยเพื่อตรวจสอบว่าไม่มีวิธีแก้ปัญหามากมายเหลือเกิน