今聞こえますか?


23

バックグラウンド

あなたはソフトウェア帝国の豊かな経営者です。あなたの時間はたくさんのお金の価値があります。そのため、常に最も効率的なルートで旅行する必要があります。ただし、幹部として、あなたは重要な電話に参加するのに多くの時間を費やします。絶対に電話を落とさないことが重要です。したがって、携帯電話サービスのないエリアを移動することはできません。

チャレンジ

3つのタプルのリストが表示されます。各タプルは、セルタワーの位置とパワーを表します。例として、影響の円を表す半径16の円で[50, 25, 16]位置<x,y> = <50, 25>するセルタワーを表します。このリストを念頭に置いて、開始位置から<0, 0>目的地に移動し<511, 511>、セルサービスを失うことなく可能な限り最短距離で移動する必要があります。これはなので、最短のコードが勝ちです!

入出力

ファイルなど、またはを使用してSTDINを介してネストされた配列として、読みやすい形式に入力を自由に操作できますeval。まあ。入力のハードコーディングに使用される正確な文字はカウントされませんが、変数名と割り当て文字はカウントされます。入力が特定の順序になっていることや、すべてのセルタワーが問題に関連していることを想定しないでください。ご質問がある場合は、コメントを残してください、私はそれを明確にしようとします。

出力は座標のリストで、接続されたときに出口へのパスを形成するポイントをマークします。精度は、最も近い整数に丸める必要があるだけで、出力例の1〜2単位離れている場合は問題ありません。これを明確にするために、以下の画像を含めました。

幸運を祈ります!

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]

タワーの場所

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

最適なパス

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]

例2

output2:
0 0
247 308
511 511

前のパスは青色で強調表示されていますが、より多くのタワーを追加すると、より最適なルートが可能になることがわかります。

溶液


2
フィニッシュは511,511を想定していますか?
MickyT 14年

2
中間点はどのくらい正確でなければなりませんか?それらは整数でなければなりませんか?
キースランドール14年

6
本当に金持ちだったら、半径182の(127、127)に塔を建設し、小さなトンネルを通り抜けて通り抜けます。
反地球14年

1
一貫性がない:宛先は255,255ですか、511,511ですか?
edc65 14年

2
何らかの準備をした後に、この問題をこの挑戦に減らすことが可能になると思います。ただし、塔のいくつかのパスがある例を追加することもできます。
マーティンエンダー14年

回答:


18

Python、 1,291 1,271 1,225バイト

マーティンが指摘したように、この問題は、彼の優れたラバーバンドの課題に大きく帰着することができます。その課題の用語を使用して、2番目の釘のセットとして、囲まれた領域の境界上の円間の交点を取得できます。

図1

ラバーバンドとして、囲まれた領域内で実行される2つのエンドポイント間の任意のパスPを使用できます。次に、ラバーバンド問題の解決策を呼び出して、(局所的に)最小のパスを作成できます。もちろん、そのようなパスPを見つけるか、より正確には、少なくとも1つがグローバルに最小のパスを生成できるように十分なパスを見つけることが課題です(最初のテストケースでは、少なくとも1つのパスが必要ですすべての可能性をカバーし、2番目のテストケースでは少なくとも2つ。)

素朴なアプローチは、すべての可能なパスを試すことです:2つの端点を接続する隣接する(つまり交差する)円のシーケンスごとに、中心に沿ってパスを取ります(2つの円が交差する場合、中心間のセグメントは常に結合内にあります) 。)このアプローチは技術的には正しいものの、途方もなく多くのパスにつながる可能性があります。私はこのアプローチを使用して最初のテストケースを数秒で解決できましたが、2番目のテストケースは永遠にかかりました。それでも、この方法を出発点として、テストする必要があるパスの数を最小限に抑えることができます。これは次のとおりです。

基本的に円グラフ上で深さ優先検索を実行することにより、パスを構築します。検索の各ステップで潜在的な検索方向を排除する方法を探しています。

ある時点で、互いに隣接している2つの隣接する円BCがある円Aにいると仮定します。BにアクセスするAからCに移動できます(逆も同様です)。したがって、AからBCの両方に直接アクセスする必要はないと考えるかもしれません。残念ながら、この図が示すように、これは間違っています。

図2

図のポイントが2つのエンドポイントである場合、Bを介してAからCに移動することにより、より長いパスが得られることがわかります。

これについてはどうでしょう:移動ABACの両方をテストする場合、ABCまたはACBをテストする必要はありません。また違う:

図3

ポイントは、純粋に隣接関係に基づいた引数を使用しても、それが削減されないということです。問題のジオメトリも使用する必要があります。上記の2つの例の共通点(および大規模な2番目のテストケース)は、囲まれた領域に「穴」があることです。それは、境界上の交点のいくつか、つまり「爪」が、頂点が円の中心である三角形△ ABCの中にあるという事実に現れています。

図4

これが発生すると、AからBに、そしてAからCに行くと、異なるパスになる可能性があります。さらに重要なこと、それが起こらない場合(つまり、AB、およびCの間にギャップがなかった場合)、ABCおよびACで始まり、それ以外の場合は同等であるすべてのパスが結果として保証されることです同じローカル最小パスで、したがってBにアクセスする場合、Aから直接Cにアクセスする必要はありません。

これは、私たちの除去方法につながります。サークルAにいるとき、私たちが訪れた隣接するサークルのリストHを保持します。このリストは最初は空です。ABの中心とBに隣接するHの円のいずれかによって形成されるすべての三角形に「爪」がある場合、隣接する円Bを訪問します。この方法では、テストする必要があるパスの数が最初のテストケースで1つ、2番目のテストケースで10に劇的に減少します。

さらにいくつかの注意事項:

  • テストするパスの数をさらに減らすことは可能ですが、この方法はこの問題の規模に十分対応できます。

  • ラバーバンドチャレンジのソリューションからアルゴリズムを使用しました。このアルゴリズムはインクリメンタルであるため、パス検索プロセスに非常に簡単に統合できるため、進行中にパスを最小化できます。多くのパスが開始セグメントを共有するため、多くのパスがある場合、これによりパフォーマンスが大幅に向上します。また、有効なパスよりも多くの行き止まりがある場合、パフォーマンスを損なう可能性があります。いずれにしても、与えられたテストケースでは、各パスのアルゴリズムを個別に実行するだけで十分です。

  • このソリューションが失敗する可能性のあるエッジケースが1つあります。境界上の点のいずれかが2つの接線円の交点である場合、ある条件下では結果が間違っている可能性があります。これは、ラバーバンドアルゴリズムの動作方法によるものです。いくつかの変更を加えることで、これらのケースを処理することもできますが、それはすでに十分な長さです。


# 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タプルの集合として円の中心であり、その半径です。値はsではなくsでなければなりません。結果はSTDOUTに出力されます。((x, y), r)(x, y)rfloatint

# 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.        ]]
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.