Daire Kavşaklarında Özel Alan Bulma


17

İşte sizin için aldatıcı zorlu bir geometri bulmacası!

Bir çevre göz önüne alındığında A, ve ndiğer çevreleri B[n]içinde, içerdiği toplam alanı bulmak Aolduğunu değil herhangi daire içinde B.

Kodunuz mümkün olduğunca kısa olmalıdır.

Giriş

Girişinizde aşağıdaki bilgiler bulunmalıdır:

  • Dairenin yarıçapını temsil eden kayan nokta sayısı A.
  • İçindeki dairelerin yarıçaplarını temsil eden kayan nokta sayılarının listesi B.
  • İçindeki çevrelerin merkezlerinin listesi B. Programınız merkezlerin kutupsal veya Kartezyen koordinatlarda olmasını bekleyebilir.
  • İsteğe bağlı olarak, nB'deki daire sayısını alabilirsiniz . Bu giriş gerekli değildir.

Dairenin merkezinin Abaşlangıç ​​noktası, yani nokta olduğu varsayılacaktır (0, 0).

İki dairenin Baynı olmadığı garanti edilir , ancak aşağıdakilerin garanti edilmez : Bkesişen tüm daireler A, tüm merkezler Bdışarıdadır AveyaB birbiriyle kesişen . Çözümünüzün çeşitli kenar durumlarını ele alabileceğinden emin olun.

Girişi herhangi bir sırada ve metin girişi (stdin veya dilinizin eşdeğeri aracılığıyla), işlev parametreleri veya komut satırı bağımsız değişkenleri şeklinde alabilirsiniz.

Metin girişi almayı seçerseniz, giriş parçaları arasında bir veya iki karakterlik yazdırılabilir ASCII sınırlayıcılar olmalıdır.

Çıktı

Programınız veya işleviniz A,B . Yanıtlarınız tüm test senaryoları için en az üç anlamlı rakama doğru olmalıdır.

Genel kuralları geçerlidir.

Çözümünüz, bir alan belirlemek için dairelerdeki örnekleme noktalarına güvenmemelidir.

Çevrelerin kesişimlerini otomatik olarak bulan, çevrelerin kesişim noktalarındaki alanları bulan veya bu sorunu hemen çözen yerleşiklere izin verilmez.

Test Durumları

Her görüntüde, daire Amavi ile, daireler Byeşil ile işaretlenmiş ve siyahla doldurulmuştur. Döndürülmesi gereken alan kırmızı ile doldurulur.

( Çözümlerimi kontrol ettiği için Rainer P.'ye özel teşekkürler )

Test örneği 1:

A = {x: 0, y: 0, rad: 50}
B[0] = {x: 0, y: 0, rad: 100}

Test durumu 1

Result: 0.00

Test örneği 2:

A = {x: 0, y: 0, rad: 100.000000}
B[0] = {x: 100.000000, y: 0.000000, rad: 50.000000}
B[1] = {x: 30.901699, y: -95.105652, rad: 50.000000}
B[2] = {x: -80.901699, y: -58.778525, rad: 50.000000}
B[3] = {x: -80.901699, y: 58.778525, rad: 50.000000}
B[4] = {x: 30.901699, y: 95.105652, rad: 50.000000}

Test durumu 2

Result: 1.3878e+04

Test örneği 3:

A = {x: 0, y: 0, rad: 138}
B[0] = {x: 100, y: 0, rad: 100}
B[1] = {x: -50, y: -86, rad: 100} 
B[2] = {x: -93, y: 135, rad: 50}

Test durumu 3

Result: 1.8969e+04

Test durumu 4:

A = {x: 0, y: 0, rad: 121.593585}
B[0] = {x: 81.000000, y: 107.000000, rad: 59.841457}
B[1] = {x: -152.000000, y: -147.000000, rad: 50.000000}
B[2] = {x: 43.000000, y: -127.000000, rad: 105.118980}
B[3] = {x: 0.000000, y: -72.000000, rad: 57.870545}
B[4] = {x: -97.000000, y: -81.000000, rad: 98.488578}
B[5] = {x: -72.000000, y: 116.000000, rad: 66.468037}
B[6] = {x: 2.000000, y: 51.000000, rad: 50.000000}

Test durumu 4

Result: 1.1264e+04

Test durumu 5:

A = {x: 0, y: 0, rad: 121.605921}
B[0] = {x: 0.000000, y: -293.000000, rad: 250.000000}
B[1] = {x: 0.000000, y: -56.000000, rad: 78.230429}
B[2] = {x: 0.000000, y: -102.000000, rad: 100.000000}

Test durumu 5

Result: 2.6742e+04

Önerilen Okuma:

Fewell, MP "Üç Çemberin Ortak Çakışma Alanı." Ekim 2006. Web.http://dspace.dsto.defence.gov.au/dspace/bitstream/1947/4551/4/DSTO-TN-0722.PR.pdf .


İki yıl önce sorunun ne kadar basit olduğuna bağlı olarak , bunu yaparken iki yıl önce kendimi çözmeye çalıştım . Bağlantı kurduğunuz makaleyi okudum ... ve Monte Carlo'ing ile gitmeye karar verdim. "Çözümünüz, bir alan belirlemek için çevrelerdeki örnekleme noktalarına güvenmemelidir." D:
Martin Ender

İçerisindeki bir dairenin Bdiğerini içerdiği bir test durumunuz yok gibi görünüyor . Bunu eklemeye değer olabilir.
Martin Ender

Üçüncü test vakanızı kontrol edebilir misiniz? Anlıyorum 1.8970e+04.
LegionMammal978

@ MartinBüttner Ben de kazada problemle karşılaştım. Çözümümden aşırı memnun değilim, ama işe yarıyor gibi görünüyor. Bu dava için küçük bir test yapmaya çalışacağım, teşekkürler!
BrainSteel

@ LegionMammal978 Evet, durum yanlış görünüyor. Halkaların arasındaki kesişme aşağıdaki verileri: B[0] - A intersection: 20653.659515, B[1] - A intersection: 20757.824115, B[1] - B[0] intersection: 1841.847766, B[2] - A intersection: 1289.164541, getirir ve burada 18969.69009cevap olarak.
BrainSteel

Yanıtlar:


14

Python 2, 631 bayt

from cmath import*
C=input()
O,R=C[0]
def I(p,r,q,s):
 try:q-=p;d=abs(q*q);x=(r*r-s*s+d)/d/2;return[p+q*(x+z*(r*r/d-x*x)**.5)for z in-1j,1j]
 except:return[]
S=sorted
V=S(i.real for p,r in C for c in C for i in[p-r,p+r]+I(p,r,*c)if-R<=(i-O).real<=R)
A=pi*R*R
for l,r in zip(V,V[1:]):
 H=[]
 for p,t in C:
    try:
     for s in-1,1:a,b=[p.imag+s*(t*t-(p.real-x)**2)**.5for x in l,r];H+=[a+b,a,b,s,t,p],
    except:0
 a,b=H[:2];H=S(H[2:]);n=0;c=a
 for d in H:
    s=d[3];z=.5;H*=d<b
    for q,w,e,_,t,y in(c,min(d,b))*(n-s<(a<d)or[0]*n>H):\
g=phase((l+w*1j-y)/(r+e*1j-y));A-=abs(g-sin(g)).real*t*t/2-z*q*(r-l);z=-z
    n-=s
    if(a<d)*s*n==-1:c=d
print A

Önce satır sonları \ kolay okuma içindir ve skorda sayılmaz.

STDIN üzerinden girişi , formdaki karmaşık bir sayı olan (center, radius)çiftlerin bir listesi olarak okur . Listedeki ilk dairedir bir (bunun merkezi kaynaklı olmak zorunda değildir) ve listenin geri kalanı B . Sonucu STDOUT olarak yazdırır.centerX+Yj

Misal

Input:  (0+0j, 138),  (100+0j, 100), (-50+-86j, 100), (-93+135j, 50)
Output: 18969.6900901

açıklama

Benim üzerinde varyasyon: Bu (P uzun ve daha çirkin) 'dir çözümü Martin BÜTTNER en etmek bir kendini kesen poligon Alanında meydan. Sorunu, daha yönetilebilir hale geldiği yeterince küçük parçalara bölmek için aynı hileyi kullanır.

Tüm daire çiftleri arasındaki kesişim noktalarını buluyoruz (hem A hem de B'deki daireler göz önünde bulundurularak) her birinden dikey bir çizgi geçiririz. Ayrıca, tüm dikey çizgileri teğet olan dairelerin herhangi birine geçiririz. A ile kesişmeyen tüm çizgileri atarız , böylece kalan tüm çizgiler A'nın sol ve sağ teğetleri arasında olur .

Şekil 1

Biz kesişme alanını arıyoruz A'nın ve B'deki dairelerin birleşimini - yukarıdaki resimde koyu kırmızı alan. Bu sonucu elde etmek için A'dan çıkartmamız gereken alandır .

Her bir ardışık dikey çizgi çifti arasında, bu alan, her bacağın yanında bir "fazla" yay segmenti ile bir dizi dikey trapezoid (veya üçgenler veya özel trapezoidler halinde çizgi segmentleri) olarak ayrılabilir. Yaptığımız kadar çok dikey çizgi geçmemiz, sınırlı alanın bundan daha karmaşık olmadığını garanti eder, aksi takdirde iki çizgi arasında ek bir kavşak noktası ve dolayısıyla ek bir dikey çizgi olması gerekir. soru.

şekil 2

Bu yamukları ve ark segmentlerini bulmak için, birbirini takip eden her dikey çizgi çifti için, bu iki çizgi arasında düzgün bir şekilde uzanan dairelerin her birinin ark segmentlerini buluruz (elbette, bazı dairelerin belirli bir çizgi çifti arasında ark segmenti olmayabilir. .) Aşağıdaki çizimde, bunlar iki kırmızı dikey çizgi göz önüne alındığında altı (parlak ve koyu) sarı ark segmentidir. Tüm dikey çizgileri dairelere teğet geçirdiğimizden, bir dairenin iki çizgi arasında bir ark segmenti varsa, mutlaka algoritmanın geri kalanını basitleştiren her iki çizgiyle kesiştiğini unutmayın.

Bu yayların hepsi ilgili değildir; sadece A ile B birliği arasındaki kesişim sınırında olanlarla ilgileniyoruz . Bunları bulmak için, yayları yukarıdan aşağıya doğru sıralarız (yayların birbirleriyle düzgün bir şekilde kesişemeyebileceğine dikkat edin, çünkü bu düşündüğümüz ikisi arasında başka bir dikey çizginin varlığını ima eder ve bu nedenle konuşmak mantıklıdır rasgele bir yayın başka herhangi birinin üstünde veya altında olması hakkında.)

Figür 3

Şu anda içinde bulunduğumuz B dairelerinin sayısını tutarken yayları sırayla geziyoruz , n . Eğer n, içeri iken 0 ile 1 arasında değişiklik A , ya da en üst yay de eğer A ise n sıfırdan farklı, bir yamuk bir bacağı daha sonra akım arkı karşılık gelir. Eğer n içeri yaparken 1'den 0'a değişiklikler A biz alt arc iseniz veya A iken nsıfır değilse, akım arkı aynı yamukun diğer ayağına karşılık gelir. Böyle bir çift kemeri bulduğumuzda (yukarıdaki çizimde iki parlak sarı yay), karşılık gelen yamuk alanını ve iki ark parçasının alanını hesaplıyoruz ve A'dan çıkarılacak toplam alana ekliyoruz .

A alanının yanı sıra yamuk alanlarının hesaplanması oldukça düzdür. Her ark segmentinin alanı, karşılık gelen dairesel sektörünün alanı, eksi köşeleri ark segmentinin iki uç noktası olan üçgenin alanı ve karşılık gelen dairenin merkezidir.

Şekil 4


1
Bu, düşündüğüm bir çeşit çözümdür, ancak hedef alanı doğrudan A'da olan ancak B'de olmayan (ve bir üçgen veya yamuktan bir yay segmenti çıkarılarak bulunması gereken) triarcları ve tuzakları bularak bulurdum.
quintopia

@kintopia Bu biraz daha kısa olabilir, çünkü bize A alanını hesaplama ihtiyacını kurtarır ve tek yapmanız gereken muhtemelen n'deki koşulla biraz oynamaktır .
Ell

@quintopia OTOH, bacaklardan birinin yanında pozitif bir ark olma olasılığını hesaba katmalısınız, eğer A'nın bir ark segmenti ise , kim bilir ...
Ell

Mükemmel çözüm. Dün gece bununla hemen hemen aynı olan bir sorun kafamda sıkışmıştı ve gerçekten birisinin bunu çözmesini istedim. Çözümünüz, üzerinde çalıştığım fikirlerden daha iyi.
Mantık Şövalyesi
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.