交差点での排他的エリアの検索


17

これは一見難しい挑戦的なジオメトリパズルです。

円与えられA、及びn他の円B[n]内に含まれる全面積見つけるAはない任意の円内をB

コードはできるだけ短くする必要があります。

入力

入力には次の情報が含まれている必要があります。

  • circleの半径を表す浮動小数点数A
  • の円の半径を表す浮動小数点数のリストB
  • の円の中心のリストB。プログラムでは、極座標またはデカルト座標のいずれかの中心を想定している場合があります。
  • オプションで、nBの円の数を受け取ることができます。この入力は必須ではありません。

円の中心がA原点、つまり点であると想定され(0, 0)ます。

の2つの円Bが同一ではないことが保証されますが、すべてのB交差する円A、すべての中心Bが外側A、または2つの円がB互いに交差しないことは保証されません。ソリューションがさまざまなエッジケースを処理できることを確認します。

入力は任意の順序で、テキスト入力(stdinまたは同等の言語を介して)、関数パラメーター、またはコマンドライン引数の形式で受け取ることができます。

テキスト入力の受信を選択した場合、入力の間に1文字または2文字の印刷可能なASCII区切り文字が必要です。

出力

プログラムまたは関数Aは、の円のいずれにも属さない総面積を表す単一の浮動小数点数を出力する必要がありますB。回答は、すべてのテストケースで少なくとも3つの有効数字に対して正確でなければなりません。

一般的な規則が適用されます。

ソリューションは、円内のサンプリングポイントに依存して領域を決定しないでください。

円の交差点を自動的に見つける、円の交差点内の領域を見つける、またはこの問題をすぐに解決する組み込み機能は許可されていません。

テストケース

各画像で、円のA輪郭は青で、円のB輪郭は緑、黒で塗りつぶされています。返されるべき領域は赤で塗りつぶされています。

(私のソリューションをチェックしてくれたRainer Pに感謝します)

テストケース1:

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

テストケース1

Result: 0.00

テストケース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}

テストケース2

Result: 1.3878e+04

テストケース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}

テストケース3

Result: 1.8969e+04

テストケース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}

テストケース4

Result: 1.1264e+04

テストケース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}

テストケース5

Result: 2.6742e+04

推奨読書:

Fewell、MP「3つの円の共通の重なりの領域」。2006年10月。ウェブ。http://dspace.dsto.defence.gov.au/dspace/bitstream/1947/4551/4/DSTO-TN-0722.PR.pdf


私は2年前にこの問題に取り組みながら、2つの円の問題がどれほど簡単かを考えて、これを自分で解決しようとしました。私はあなたがリンクした論文を読んでしまいました...そして、モンテカルロでこの地域に行くことにしました。「あなたの解決策は、領域を決定するために円内のサンプリングポイントに依存すべきではありません。」D:
マーティン・エンダー

1つの円にB別の円が含まれるテストケースはないようです。それを追加する価値があるかもしれません。
マーティンエンダー

3番目のテストケースを確認できますか?私は得てい1.8970e+04ます。
LegionMammal978

@MartinBüttner私も事故で問題に遭遇しました。私は自分のソリューションにあまり満足していませんが、うまくいくようです。その場合のために、ちょっとしたテストを作成してみます、ありがとう!
BrainSteel

@ LegionMammal978はい、大文字と小文字が間違っているようです。私は、円との交点には次のデータを持っている: B[0] - A intersection: 20653.659515B[1] - A intersection: 20757.824115B[1] - B[0] intersection: 1841.847766B[2] - A intersection: 1289.164541、得た18969.69009答えとして。
BrainSteel

回答:


14

Python 2、631バイト

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

で始まる改行は\読みやすくするためのものであり、スコアにはカウントされません。

STDINを介して入力を(center, radius)ペアのリストとして読み取ります。ここでcenterはの形式の複素数X+Yjです。リストの最初の円はA(中心は原点にある必要はありません)で、リストの残りの部分はBです。結果をSTDOUTに出力します。

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

説明

これは、MartinBüttner の自己交差ポリゴンチャレンジの領域に対する私のソリューションの(より長く、はるかにugい:P)バリエーションです。問題を小さな十分な部分に分解するという同じトリックを使用して、それをより管理しやすくします。

すべての円のペア間の交差点を見つけ(ABの円の両方を考慮)、それらのそれぞれを通る垂直線を渡します。さらに、すべての円に接するすべての垂直線を渡します。Aと交差しないすべての線を捨て、残りのすべての線がAの左右の接線の間にあるようにします。

図1

ABの円の結合の交点の領域を探しています。上の図の濃い赤色の領域です。これは、結果を得るためにAから差し引かなければならない領域です。

連続する垂直線の各ペア間で、この領域を垂直脚形(または三角形、または台形の特殊なケースとしての線分)のセットに分割し、各脚の隣に「余分な」円弧セグメントを配置できます。私たちができる限り多くの垂直線を渡すという事実は、境界領域が実際にそれ以上複雑ではないことを保証します。さもなければ、追加の交点、したがって追加の垂直線が2つの線の間になければならないからです質問。

図2

これらの台形と円弧セグメントを見つけるには、連続する垂直線の各ペアについて、これらの2つの線の間に適切に位置する各円の円弧セグメントを見つけます(もちろん、特定の線のペア間に円弧セグメントがない場合もあります。)下の図では、2つの赤い垂直線を考慮すると、これらは6つの(明るいおよび暗い)黄色の円弧セグメントです。円に接するすべての垂直線を渡すため、円が2つの線の間に円弧セグメントを持っている場合、必然的に両方の線と交差するため、残りのアルゴリズムが簡素化されることに注意してください。

これらのアークのすべてが関連するわけではありません。ABの結合の交差点の境界にあるものにのみ興味があります。それらを見つけるために、アークを上から下に並べます(アークは互いに適切に交差しない場合があります。これは、検討している2つの間に別の垂直線が存在することを意味するためです。任意のアークが他のアークの上または下にあることについて)

図3

現在内側にあるB円の数nのカウントを維持しながら、順番にアークをトラバースします。Aの内側にいる間にnが0から1に変化した場合、またはnがゼロ以外のときにAの上の弧にある場合、現在の弧は台形の1つの脚に対応します。Aの内側にいる間にnが1から0に変化した場合、またはn 間にAの下の弧にある場合ゼロ以外の場合、現在の円弧は同じ台形の他の脚に対応します。このような円弧のペア(上の図の2つの明るい黄色の円弧)が見つかったら、対応する台形の面積と2つの円弧セグメントの面積を計算し、Aから減算する合計面積に追加します。

Aの面積と台形の面積の計算は、かなり簡単です。各円弧セグメントの面積は、対応する円形扇形の面積から、頂点が円弧セグメントの2つの端点である三角形の面積と、対応する円の中心を引いた面積です。

図4


1
これは私が考えていた種類の解決策です。ただし、AではなくBであるトライアークとトラペアックを見つけることでターゲットエリアを直接見つけたはずです(エリアは三角形または台形からアークセグメントを差し引くことで見つけなければなりません)。
キントピア

@quintopia Aの面積を計算する必要がなくなるため、これは少し短くなる場合があります。必要なのは、おそらくnの条件で少し遊ぶだけです。
エル

@quintopia OTOH、Aの円弧セグメントである場合、脚の1つに正の円弧がある可能性を考慮する必要があります。だから誰が知っている
Ell

優れたソリューション。昨夜、これとほぼ同じ問題が頭に残っていたので、誰かにそれを解決してもらいたかったのです。あなたのソリューションは、私が取り組んでいたアイデアよりも優れています。
ロジックナイト
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.