अजगर, 1,291 1,271 1,225 बाइट्स
जैसा कि मार्टिन ने कहा, यह समस्या काफी हद तक उनकी उत्कृष्ट रबर बैंड चुनौती को कम कर सकती है । उस चुनौती की शब्दावली का उपयोग करते हुए, हम नाखून के दूसरे सेट के रूप में एन्कोडिंग क्षेत्र की सीमा पर हलकों के बीच चौराहे के बिंदुओं को ले सकते हैं :
रबर बैंड के रूप में हम संलग्न क्षेत्र के अंदर चलने वाले दो समापन बिंदुओं के बीच कोई भी पथ P ले सकते हैं । हम तब (स्थानीय रूप से) न्यूनतम पथ का उत्पादन करने के लिए रबर-बैंड समस्या के समाधान का आह्वान कर सकते हैं। चुनौती, निश्चित रूप से, इस तरह के पथ P को खोजने के लिए , या अधिक सटीक रूप से, पर्याप्त पथ खोजने के लिए है ताकि कम से कम उनमें से एक विश्व स्तर पर न्यूनतम पथ का निर्माण करे (ध्यान दें कि पहले परीक्षण-मामले में हमें कम से कम एक पथ की आवश्यकता है सभी संभावनाओं को कवर करें, और दूसरे टेस्ट-केस में कम से कम दो।)
एक भोली दृष्टिकोण केवल सभी संभव रास्तों को आज़माने के लिए होगा: आसन्न (यानी प्रतिच्छेद) हलकों के प्रत्येक अनुक्रम के लिए जो दो समापन बिंदुओं को जोड़ता है, अपने केंद्रों के साथ पथ लें (जब दो वृत्त प्रतिच्छेद करते हैं, तो उनके केंद्रों के बीच का खंड हमेशा आपके संघ के भीतर होता है ।) हालांकि यह दृष्टिकोण तकनीकी रूप से सही है, यह हास्यास्पद रूप से बड़ी संख्या में पथ को जन्म दे सकता है। जब मैं कुछ सेकंड के भीतर इस दृष्टिकोण का उपयोग करके पहले टेस्ट-केस को हल करने में सक्षम था, तो दूसरा हमेशा के लिए ले गया। फिर भी, हम इस पद्धति को एक प्रारंभिक बिंदु के रूप में ले सकते हैं और हमारे द्वारा परीक्षण किए जाने वाले पथों की संख्या को कम करने का प्रयास करते हैं। इस प्रकार है।
हम अपने पथों का निर्माण मूल रूप से मंडलियों के ग्राफ पर गहराई से पहली खोज करके करते हैं। हम खोज के प्रत्येक चरण में संभावित खोज निर्देशों को समाप्त करने का एक तरीका खोज रहे हैं।
मान लीजिए कि किसी बिंदु पर हम एक वृत्त A पर हैं , जिसके दो समीपवर्ती वृत्त B और C हैं , जो एक दूसरे से सटे हुए हैं। B (और इसके विपरीत) पर जाकर हम A से C तक प्राप्त कर सकते हैं, इसलिए हम सोच सकते हैं कि A से सीधे B और C दोनों का दौरा अनावश्यक है। दुर्भाग्य से, यह गलत है, क्योंकि यह चित्रण दिखाता है:
यदि दृष्टांत में दिए गए बिंदु दो अंत बिंदु हैं, तो हम देख सकते हैं कि A से C तक B से होकर हमें एक लंबा रास्ता मिलता है।
इस बारे में कैसा है: यदि हम दोनों चालों का परीक्षण कर रहे हैं A → B और A → C , तो A → B → C या A → C → B का परीक्षण करना अनावश्यक है , क्योंकि उनका परिणाम छोटे पथ नहीं हो सकते। फिर से गलत:
मुद्दा यह है कि विशुद्ध रूप से आसन्न-आधारित तर्कों का उपयोग करने से इसमें कटौती नहीं होगी; हमें समस्या की ज्यामिति का भी उपयोग करना होगा। ऊपर दिए गए दो उदाहरणों में क्या आम है (साथ ही बड़े पैमाने पर दूसरा परीक्षण-मामला), यह है कि संलग्न क्षेत्र में एक "छेद" है। यह इस तथ्य में स्वयं को प्रकट करता है कि सीमा पर कुछ बिंदुओं के प्रतिच्छेदन - हमारे "नाखून" - त्रिभुज the एबीसी के भीतर जिनके कोने वृत्त के केंद्र हैं:
जब ऐसा होता है, तो एक मौका होता है कि ए से बी और ए से सी तक जाने के लिए अलग-अलग रास्ते होंगे। इससे भी महत्वपूर्ण बात यह है कि जब ऐसा नहीं होता है (अर्थात यदि A , B और C के बीच कोई अंतर नहीं था ) तो इसकी गारंटी है कि सभी रास्ते A → B → C और A → C से शुरू होते हैं और जो अन्यथा समतुल्य हैं। समान रूप से न्यूनतम पथ में, इसलिए यदि हम B पर जाते हैं तो हमें C को A से सीधे आने की भी आवश्यकता नहीं है ।
यह हमें हमारे उन्मूलन के तरीके की ओर ले जाता है: जब हम एक सर्कल A पर होते हैं , तो हम अपने पास आने वाले हलकों के H की सूची रखते हैं । यह सूची शुरू में खाली है। यदि हम A , B के केंद्रों और H से B के समीप के किसी भी मंडल में बने सभी त्रिकोणों में कोई "नाखून" हैं, तो हम निकटवर्ती वृत्त 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
टुपल्स के एक सेट के रूप में चर के माध्यम से दिया जाता है ((x, y), r)
जहां (x, y)
सर्कल का केंद्र है और r
इसका त्रिज्या है। मूल्यों को float
एस होना चाहिए , int
एस नहीं । परिणाम को 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. ]]