งูหลาม 1,291 1,271 1,225 ไบต์
มาร์ตินตั้งข้อสังเกตปัญหานี้สามารถลดลงส่วนใหญ่จะยอดเยี่ยมของเขายางวงท้าทาย การใช้คำศัพท์ของความท้าทายนั้นเราสามารถใช้เป็นชุดที่สองของเล็บจุดตัดระหว่างวงกลมในขอบเขตของพื้นที่ปิดล้อม:
ในฐานะที่เป็นแถบยางเราสามารถใช้พา ธPใดก็ได้ระหว่างจุดปลายสองจุดที่วิ่งภายในพื้นที่ปิดล้อม จากนั้นเราสามารถเรียกใช้วิธีการแก้ปัญหาแถบยางเพื่อสร้างเส้นทางที่น้อยที่สุด (ในพื้นที่) แน่นอนว่าความท้าทายคือการหาเส้นทางPหรือแม่นยำกว่านี้เพื่อหาเส้นทางที่เพียงพอเพื่อให้อย่างน้อยหนึ่งในนั้นสร้างเส้นทางที่น้อยที่สุดทั่วโลก (โปรดทราบว่าในกรณีทดสอบแรกเราต้องมีอย่างน้อยหนึ่งเส้นทางที่จะ ครอบคลุมความเป็นไปได้ทั้งหมดและในกรณีทดสอบที่สองอย่างน้อยสอง)
วิธีการที่ไร้เดียงสาคือการลองเส้นทางที่เป็นไปได้ทั้งหมด: สำหรับทุกลำดับของวงกลมที่อยู่ติดกัน (เช่นการตัดกัน) ที่เชื่อมต่อจุดปลายทั้งสองให้ใช้เส้นทางไปตามศูนย์กลางของพวกเขา (เมื่อวงกลมสองวงตัดกัน .) แม้ว่าวิธีการนี้จะถูกต้องทางเทคนิค แต่ก็สามารถนำไปสู่เส้นทางจำนวนมากได้อย่างน่าขัน ในขณะที่ฉันสามารถแก้ปัญหากรณีทดสอบครั้งแรกโดยใช้วิธีนี้ภายในไม่กี่วินาที ถึงกระนั้นเราสามารถใช้วิธีนี้เป็นจุดเริ่มต้นและพยายามลดจำนวนเส้นทางที่เราต้องทดสอบ นี่คือสิ่งที่ตามมา
เราสร้างเส้นทางของเราโดยการทำการค้นหาเชิงลึกครั้งแรกบนกราฟของวงกลม เรากำลังมองหาวิธีกำจัดทิศทางการค้นหาที่อาจเกิดขึ้นในแต่ละขั้นตอนของการค้นหา
สมมติว่าในบางจุดเราอยู่ที่วงกลมAซึ่งมีวงกลมสองวงที่อยู่ติดกันBและCซึ่งอยู่ติดกัน เราสามารถได้รับจากAถึงCโดยไปที่B (และในทางกลับกัน) ดังนั้นเราอาจคิดว่าการไปที่BและCโดยตรงจากAนั้นไม่จำเป็น น่าเสียดายนี่เป็นสิ่งที่ผิดเนื่องจากภาพประกอบนี้แสดง:
หากคะแนนในภาพประกอบเป็นจุดสิ้นสุดสองจุดเราจะเห็นได้ว่าการไปจากAถึงCถึงBผ่านBเราจะได้เส้นทางที่ยาวขึ้น
ถ้าเราทดสอบทั้งการเคลื่อนไหวA → BและA → Cก็ไม่จำเป็นที่จะต้องทดสอบA → B → CหรือA → C → Bเนื่องจากพวกมันไม่สามารถทำให้เกิดเส้นทางที่สั้นกว่าได้ ผิดอีกครั้ง:
ประเด็นก็คือการใช้อาร์กิวเมนต์ที่ใช้ถ้อยคำล้วนๆจะไม่ตัดทิ้ง เราต้องใช้เรขาคณิตของปัญหาเช่นกัน สิ่งที่ทั้งสองตัวอย่างข้างต้นมีเหมือนกัน (เช่นเดียวกับกรณีทดสอบที่สองในระดับที่ใหญ่กว่า) คือมี "รู" ในพื้นที่ปิดล้อม มันปรากฏตัวในความจริงที่ว่าบางจุดของการแยกบนขอบเขต - "เล็บ" ของเรา - อยู่ภายในสามเหลี่ยม within ABCซึ่งจุดยอดเป็นศูนย์กลางของวงกลม:
เมื่อสิ่งนี้เกิดขึ้นมีโอกาสที่จะไปจากAถึงBและจากAถึงCจะส่งผลให้เกิดเส้นทางที่แตกต่างกัน ที่สำคัญกว่านั้นเมื่อมันไม่เกิดขึ้น (เช่นถ้าไม่มีช่องว่างระหว่างA , BและC ) ดังนั้นจึงรับประกันได้ว่าเส้นทางทั้งหมดที่เริ่มต้นด้วยA → B → CและA → Cและสิ่งใดที่เทียบเท่าจะส่งผลให้ ในเส้นทางที่น้อยที่สุดในประเทศเดียวกันด้วยเหตุนี้ถ้าเราไปBเราไม่จำเป็นต้องไปเยี่ยมชมยังCโดยตรงจาก
สิ่งนี้นำเราไปสู่วิธีการกำจัดของเรา: เมื่อเราอยู่ในแวดวงAเราจะเก็บรายการHของวงกลมที่อยู่ติดกันที่เราเคยเยี่ยมชม รายการนี้ว่างเปล่าเริ่มแรก เราแวะไปวงกลมที่อยู่ติดกันBถ้ามี "เล็บ" ในทุกรูปสามเหลี่ยมที่เกิดขึ้นจากศูนย์ของ, Bและใด ๆ ของวงการในHติดกับB วิธีนี้ลดจำนวนเส้นทางที่เราต้องทดสอบเหลือเพียง 1 ในกรณีทดสอบแรกและ 10 ในเส้นทางที่สองอย่างมาก
หมายเหตุเพิ่มเติม:
เป็นไปได้ที่จะลดจำนวนเส้นทางที่เราทดสอบให้มากขึ้น แต่วิธีนี้ดีพอสำหรับขนาดของปัญหานี้
ฉันใช้อัลกอริทึมจากวิธีแก้ปัญหาของฉันไปยังความท้าทายของยางรัด เนื่องจากอัลกอริทึมนี้เพิ่มขึ้นจึงสามารถรวมเข้ากับกระบวนการค้นหาเส้นทางได้อย่างง่ายดายเพื่อให้เราลดเส้นทางที่จะไป เนื่องจากเส้นทางจำนวนมากแบ่งปันส่วนเริ่มต้นสิ่งนี้สามารถปรับปรุงประสิทธิภาพได้อย่างมากเมื่อเรามีเส้นทางจำนวนมาก นอกจากนี้ยังอาจส่งผลกระทบต่อประสิทธิภาพการทำงานหากมีจุดจบมากกว่าเส้นทางที่ถูกต้อง ทั้งสองวิธีสำหรับกรณีทดสอบที่กำหนดซึ่งดำเนินการอัลกอริทึมสำหรับแต่ละเส้นทางแยกกันนั้นดีพอ
มีกรณีขอบหนึ่งที่การแก้ปัญหานี้อาจล้มเหลว: หากมีจุดใดในขอบเขตเป็นจุดตัดของวงกลมสองวงสัมผัสกันแล้วภายใต้เงื่อนไขบางอย่างผลลัพธ์อาจผิด นี่เป็นเพราะวิธีการทำงานของแถบยาง ด้วยการปรับเปลี่ยนบางอย่างเป็นไปได้ที่จะจัดการกับกรณีเหล่านี้เช่นกัน แต่นรกมันมีความยาวพอสมควรแล้ว
# First test case
I={((32.,42.),64.),((112.,99.),59.),((141.,171.),34.),((157.,191.),28.),((177.,187.),35.),((244.,168.),57.),((289.,119.),20.),((299.,112.),27.),((354.,59.),58.),((402.,98.),23.),((429.,96.),29.),((424.,145.),34.),((435.,146.),20.),((455.,204.),57.),((430.,283.),37.),((432.,306.),48.),((445.,349.),52.),((424.,409.),59.),((507.,468.),64.)}
# Second test case
#I={((32.,42.),64.),((112.,99.),59.),((141.,171.),34.),((157.,191.),28.),((177.,187.),35.),((244.,168.),57.),((289.,119.),20.),((299.,112.),27.),((354.,59.),58.),((402.,98.),23.),((429.,96.),29.),((424.,145.),34.),((435.,146.),20.),((455.,204.),57.),((430.,283.),37.),((432.,306.),48.),((445.,349.),52.),((424.,409.),59.),((507.,468.),64.),((180.,230.),39.),((162.,231.),39.),((157.,281.),23.),((189.,301.),53.),((216.,308.),27.),((213.,317.),35.),((219.,362.),61.),((242.,365.),42.),((288.,374.),64.),((314.,390.),53.),((378.,377.),30.),((393.,386.),34.)}
from numpy import*
V=array;X=lambda u,v:u[0]*v[1]-u[1]*v[0];L=lambda v:dot(v,v)
e=V([511]*2)
N=set()
for c,r in I:
for C,R in I:
v=V(C)-c;d=L(v)
if d:
a=(r*r-R*R+d)/2/d;q=r*r/d-a*a
if q>=0:w=V(c)+a*v;W=V([-v[1],v[0]])*q**.5;N|={tuple(t)for t in[w+W,w-W]if all([L(t-T)>=s**2-1e-9 for T,s in I])}
N=map(V,N)
def T(a,b,c,p):H=[X(p-a,b-a),X(p-b,c-b),X(p-c,a-c)];return min(H)*max(H)>=0
def E(a,c,b):
try:d=max((X(n-a,b-a)**2,id(n),n)for n in N if T(a,b,c,n)*X(n-b,c-b)*X(n-c,a-c))[2];A=E(a,c,d);B=E(d,c,b);return[A[0]+[d]+B[0],A[1]+[sign(X(c-a,b-c))]+B[1]]
except:return[[]]*2
def P(I,c,r,A):
H=[];M=[""]
if L(c-e)>r*r:
for C,R in I:
if L(C-c)<=L(r+R)and all([L(h-C)>L(R+s)or any([T(c,C,h,p)for p in N])for h,s in H]):v=V(C);H+=[(v,R)];M=min(M,P(I-{(C,R)},v,R,A+[v]))
return M
A+=[e]*2;W=[.5]*len(A)
try:
while 1:
i=[w%1*2or w==0for w in W[2:-2]].index(1);u,a,c,b,v=A[i:i+5];A[i+2:i+3],W[i+2:i+3]=t,_=E(a,c,b);t=[a]+t+[b]
for p,q,j,k in(u,a,1,i+1),(v,b,-2,i+len(t)):x=X(q-p,c-q);y=X(q-p,t[j]-q);z=X(c-q,t[j]-q);d=sign(j*z);W[k]+=(x*y<=0)*(x*z<0 or y*z>0)*(x!=0 or d*W[k]<=0)*(y!=0 or d*W[k]>=0)*d
except:return[sum(L(A[i+1]-A[i])**.5for i in range(len(A)-1)),id(A),A]
print V(P(I,e*0,0,[e*0]*2)[2][1:-1])
อินพุตถูกส่งผ่านตัวแปรI
เป็นชุดของ tuples ((x, y), r)
โดยที่(x, y)
เป็นจุดศูนย์กลางของวงกลมและr
เป็นรัศมี ค่าต้องเป็นfloat
s ไม่ใช่int
s ผลลัพธ์ถูกพิมพ์ไปยัง STDOUT
ตัวอย่าง
# First test case
I={((32.,42.),64.),((112.,99.),59.),((141.,171.),34.),((157.,191.),28.),((177.,187.),35.),((244.,168.),57.),((289.,119.),20.),((299.,112.),27.),((354.,59.),58.),((402.,98.),23.),((429.,96.),29.),((424.,145.),34.),((435.,146.),20.),((455.,204.),57.),((430.,283.),37.),((432.,306.),48.),((445.,349.),52.),((424.,409.),59.),((507.,468.),64.)}
[[ 0. 0. ]
[ 154.58723733 139.8329183 ]
[ 169.69950891 152.76985495]
[ 188.7391093 154.02738541]
[ 325.90536774 109.74141936]
[ 382.19108518 109.68789517]
[ 400.00362897 120.91319495]
[ 511. 511. ]]