Python, 1.291 1.271 1.225 bayt
Martin'in belirttiği gibi, bu sorun büyük ölçüde mükemmel lastik bant mücadelesine indirgenebilir . Bu zorluğun terminolojisini kullanarak, ikinci set olarak ekteki alanın sınırındaki daireler arasındaki kesişim noktalarını çivileştirebiliriz:
Lastik bant olarak , kapalı alanın içinden geçen iki uç nokta arasındaki herhangi bir P yolunu alabiliriz . Daha sonra (yerel olarak) asgari bir yol üretmek için lastik bant sorununa bir çözüm önerebiliriz. Buradaki zorluk elbette böyle bir P yolu bulmak veya daha kesin olarak, en az birisinin dünya çapında en az yolu üretmesi için yeterli yolları bulmaktır . tüm olasılıkları kapsar ve ikinci test durumunda en az iki tane)
Saf bir yaklaşım sadece tüm olası yolları denemek olacaktır: İki bitiş noktasını birbirine bağlayan her bitişik (yani kesişen) dairelerin dizisi için, merkezleri boyunca ilerleyin (iki daire kesiştiğinde, merkezleri arasındaki segment her zaman birliktelikleri arasındadır) .) Bu yaklaşım teknik olarak doğru olsa da, gülünç derecede çok sayıda patika yol açabilir. Bu yaklaşımı kullanarak ilk test senaryosunu birkaç saniye içinde çözebildiğim halde, ikincisi sonsuza dek sürdü. Yine de, bu yöntemi bir başlangıç noktası olarak ele alabilir ve test etmek zorunda olduğumuz yol sayısını en aza indirmeyi deneyebiliriz. İşte budur.
Yollarımızı temel olarak çevrelerin grafiği üzerinde derinlemesine ilk bir arama yaparak gerçekleştiriyoruz. Potansiyel arama talimatlarını, aramanın her aşamasında ortadan kaldırmanın bir yolunu arıyoruz.
Bir daire konum bir noktada varsayalım A iki bitişik daireler vardır, B ve C aynı zamanda birbirine bitişiktir. Biz alabilirsiniz A için C ziyaret ederek B biz bu ziyaret hem düşünebilir böylece (, tersi ve yardımcısı) B ve C doğrudan gelen A gereksizdir. Ne yazık ki, bu resimde gösterildiği gibi, bu yanlış:
Resimde noktaları iki bitiş noktaları isek, dan giderek görebilirsiniz A için C aracılığıyla B biz daha uzun bir yol olsun.
Buna ne dersiniz: A → B ve A → C hareketlerini test ediyorsak , daha kısa yollarla sonuçlanamadıkları için A → B → C veya A → C → B testlerini test etmek gerekli değildir. Tekrar yanlış:
Mesele şu ki, tamamen bitişik tabanlı argümanlar kullanmanın bunu kesmeyeceği; Problemin geometrisini de kullanmak zorundayız. Yukarıdaki iki örneğin ortak yanı (ve daha büyük ölçekte ikinci test durumu), ekteki alanda bir "delik" olmasıdır. Sınırdaki kesişme noktalarından bazılarının - "çivilerimiz" - köşeleri dairelerin merkezleri olan ABC △ ABC üçgeninde olduğu gerçeğini gösterir.
Bu durumda, giden bir şans var A'ya kadar B ve gelen A için C farklı yollar ile sonuçlanacaktır. Daha da önemlisi, olmadığında (yani A , B ve C arasında bir boşluk olmasaydı ), o zaman A → B → C ve A → C ile başlayan ve aksi takdirde eşdeğer olan tüm yolların ortaya çıkacağı garanti edilir. Aynı şekilde yerel olarak minimum yolda, B'yi ziyaret edersek, C'yi doğrudan A'dan da ziyaret etmemize gerek kalmaz .
Bu bizi eleme yöntemimize yönlendirir: A dairesindeyken , ziyaret ettiğimiz bitişik çevrelerin H listesini tutarız. Bu liste başlangıçta boştur. Bu, bitişik daire ziyaret B herhangi bir "çivi" varsa tüm merkezleri tarafından oluşturulan üçgenler bir , B ve çevrelerinin bir H bitişik B . Bu yöntem, ilk test aşamasında sadece 1'e, ikinci durumda ise 10'a test etmek zorunda olduğumuz yol sayısını çarpıcı bir şekilde düşürüyor.
Birkaç not daha:
Test ettiğimiz yol sayısını daha da azaltmak mümkündür, ancak bu yöntem bu sorunun ölçeği için yeterince iyidir.
Ben gelen algoritma kullanılmıştır benim çözüm lastik bant meydan. Bu algoritma artımlı olduğu için, yol bulma sürecine kolayca entegre edilebilir, böylece devam ettikçe yolu en aza indiririz. Birçok yol bir başlangıç segmentini paylaştığından, bu, birçok yolumuz olduğunda performansı önemli ölçüde artırabilir. Geçerli yollardan çok daha fazla çıkmaz varsa performansı da düşürebilir. Her iki durumda da, verilen test durumları için her bir yol için algoritmayı ayrı ayrı yapmak yeterlidir.
Bu çözümün başarısız olabileceği bir durum var: Sınırdaki noktalardan herhangi biri iki teğet çemberin kesiştiği nokta ise, o zaman bazı koşullar altında sonuç yanlış olabilir. Bunun nedeni lastik bant algoritmasının çalışmasıdır. Bazı değişikliklerle bu davaları da ele almak mümkün, ama cehennem, zaten yeterince uzun.
# 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])
Giriş değişkeni üzerinden verilir I
dizilerini kümesi olarak dairenin merkezi ve onun yarıçapıdır. Değerler s olmalı, s değil . Sonuç STDOUT'a yazdırılır.((x, y), r)
(x, y)
r
float
int
Örnek
# 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. ]]