Şimdi beni duyabiliyor musun?


23

Arka fon

Bir yazılım imparatorluğunun zengin bir yöneticisisin. Zamanınız çok paraya değer. Bu nedenle, her zaman mümkün olan en verimli rotada seyahat etmelisiniz. Ancak, bir yönetici olarak, önemli telefon görüşmelerine katılmak için çok zaman harcıyorsunuz. Asla aramaları bırakmamanız çok önemli, bu yüzden asla hücre servisi olmayan alanlarda seyahat etmemelisiniz!

Meydan okuma

Her biri bir hücre kulesinin yerini ve gücünü temsil eden üçlü bir liste verilecektir. Örnek olarak, etki çemberini temsil eden yarıçapı 16 olan bir dairede [50, 25, 16]bulunan bir hücre kulesini <x,y> = <50, 25>temsil edecektir. Bu liste akılda tutularak, başlangıç ​​konumunuzdan <0, 0>varış yerinize <511, 511>, kısa sürede hücre servisini kaybetmeden seyahat etmelisiniz . Bu , yani en kısa kod kazanır!

Giriş çıkış

Girdiyi, bir dosyada veya STDIN aracılığıyla iç içe dizilmiş bir dizide olduğu gibi okunmasını kolaylaştıran bir forma dönüştürmekte özgürsünüz eval. Kodunuz diğer girişler için çalıştığı sürece girdiyi kodlayabilirsiniz. iyi. Girdiyi kodlamak için kullanılan tam karakterler sayılmaz, ancak değişken adı ve atama karakterleri kullanılır. Girişin belirli bir düzende olduğunu veya her hücre kulesinin sorunla ilgili olduğunu varsaymamalısınız. Herhangi bir sorunuz varsa, bir yorum bırakın lütfen açıklığa kavuşturmaya çalışacağım.

Çıktı, sırayla bağlandığında çıkışa giden yolu işaretleyen noktaları işaretleyen bir koordinat listesi olacaktır. Doğruluk sadece en yakın tam sayıya yuvarlanmalıdır ve içimdeki çıktıdan 1-2 birim uzaktaysanız, sorun değil. Bunu netleştirmek için aşağıdaki görüntüleri ekledim.

İyi şanslar!

Örnekler

input:
[ 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]

Kule Yerleri

output:
0 0
154 139
169 152
189 153
325 110
381 110
400 120
511 511

Optimal Yol

input2
[ 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]

Örnek 2

output2:
0 0
247 308
511 511

Önceki yol mavi ile vurgulanır, ancak daha fazla kulenin eklenmesinin daha uygun bir rota sağladığını görebilirsiniz.

Çözüm


2
Bitiş 511,511 mi olmalı?
MickyT

2
Ara noktalar ne kadar doğru olmalı? Tamsayılar olmalı mı?
Keith Randall

6
Gerçekten çok zengin olsaydım, yarıçapı 182 ile küçük bir tünele sahip bir kule inşa ederim (127, 127).
Anti Dünya,

1
tutarlı değil: Hedef 255,255 veya 511,511 mi?
edc65

2
Bazı hazırlıklardan sonra bu sorunu bu zorluğa indirmenin mümkün olabileceğini düşünüyorum . Yine de birkaç kule yolu olan bir örnek eklemek isteyebilirsiniz.
Martin Ender

Yanıtlar:


18

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:

Şekil 1

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ış:

şekil 2

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: AB ve AC hareketlerini test ediyorsak , daha kısa yollarla sonuçlanamadıkları için ABC veya ACB testlerini test etmek gerekli değildir. Tekrar yanlış:

Figür 3

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 ABCABC üçgeninde olduğu gerçeğini gösterir.

Şekil 4

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 ABC ve AC 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 Idizilerini 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)rfloatint

Ö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.        ]]
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.