凸包の点(2D)


10

バックグラウンド

凸包点の有限数の頂点として、または内部のいずれかで、点のすべてを含む最小の凸多角形です。詳細については、非常によく定義されているPGMに関するこの質問を参照してください。

入力

N+1N >= 3通過した2次元座標()STDINは、次の形式で(他の通常のゴルフ入力も許可されます)渡されます(小数点以下の桁数は異なる場合がありますが、「妥当」であり、各数値は浮動小数点数として表すことができると想定できます)。

0.00;0.00000
1;0.00
0.000;1.0000
-1.00;1.000000

出力

STDOUTリストの最初のポイント((0.00;0.00000)上記の例)が他のNポイントの凸包にある場合に出力される(または同等の)真の値、それ以外の場合は偽の値。

これはなので、バイト単位の最短のソリューションが優先されます。

  • ボーダーケース:ポイントが凸包の境界にある場合(クラッシュしない)、任意の値を返すことができます。これは、確率がゼロであるため、凸包の側面またはハルの外側の境界の頂点にある場合です。イベント(妥当な確率で)。

  • 禁止:幾何学的問題を解決するためにのみ存在するもの(言語、演算子、データ構造、組み込み、またはパッケージ)(例:MathematicaのConvexHull)。汎用数学ツール(ベクトル、行列、複素数など)が許可されています。

テスト


3
「アドホックデータ構造」とは何ですか?
DavidC、2015

「初等関数/演算子」はあいまいすぎます。
xnor

@DavidCarraher:ポリゴン、三角形、セグメントなど(幾何学的問題を解決するためにのみ存在するもの)。
Alexandre Halm

2
@AlexandreHalmあなたの編集は非常に役に立ちました。「小学校」は正しい言葉ではないと思います。sortまたはのような汎用ビルトインを削除すると思いましたround。ジオメトリのために特別に作られたものは何も許可されていないとだけ言った方が明確だと思います。しかし、2つのリストをベクトルとして追加する関数についてはどうでしょうか。または、複素数の引数(角度)を見つける関数ですか?
XNOR

1
これが、ダイアモンドが新しいチャレンジを投稿する前にサンドボックス使用するようリクエストする理由です。

回答:


9

J、 40 39 34バイト

3 :'(o.1)<(>./-<./)12 o.y*+{.y'@:-

匿名進機能、ポイントを取って、P、引数の1つ、およびポイントのリストとして、P他の引数として、(それがどのある引数問題ではない)、および返却0または1場合、pは外にありますか凸包内部Pそれぞれ。点pPの点は複素数として扱われます。

  is_inside =: 3 :'(o.1)<(>./-<./)12 o.y*+{.y'@:-

  0.5j0.5  is_inside  0j0 0j1 1j0 1j1
1
  1.5j0.5  is_inside  0j0 0j1 1j0 1j1
0

または...

Python 2、関数、 121 103、完全なプログラム、 162

Python 3、149バイト

import sys,cmath as C
p,q,*P=[complex(*eval(l.replace(*";,")))for l in sys.stdin]
A=[C.phase((r-p)/(q-p+(q==p)))for r in P]
print(max(A)-min(A)>C.pi)

STDINを介して、元の投稿と同じ形式で入力を受け取り、pがPの凸包にあるかどうかを示すブール値を出力します。


説明

プログラムの最大値と最小値(符号付き)との差が任意の点の間の角度か否かをテストRにおけるPP、および固定された任意の点QにおけるPは、(先ほどの最初の点を使用Pを)未満180°。言い換えると、Pのすべての点がpを中心に180°以下の角度で含まれているかどうかをテストします。 この条件が偽の場合に限り、pPの凸包にあります。


さらに数バイトのコストで、角度を明示的に計算する必要のない同様の方法を使用できます。上記の条件は、存在する場合に限り、pPの凸包の外側にあることを示すことに相当します。Pのすべての点がlの同じ側​​にあるような、lからpまでの線。そのような行が存在する場合、その後の点の1つ(または複数)に入射するようなAラインもあるPは、(我々が回転可能Lは、それがの点のいずれかに触れるまでPを。)

この線を(暫定的に)見つけるために、lpを通る線とPの最初の点とすることから始めます。次に、Pの残りの点を反復処理します。ポイントの1つがlの左側にある場合(全体の方向性を想定し、左または右は実際には問題ではありません)、lpとそのポイントを通過する線で置き換え、続行します。すべてのPを繰り返した後、pが凸包の外にある場合(かつその場合のみ)、Pのすべての点はlの右側(または上)にある必要があります。のポイントをもう一度通過することを確認しPます。

Python 2、172バイト

import sys
P=[eval(l.replace(*";,"))for l in sys.stdin]
x,y=P.pop(0)
C=lambda(a,b),(c,d):(a-x)*(d-y)-(b-y)*(c-x)>0
l=reduce(lambda*x:x[C(*x)],P)
print any(C(l,q)for q in P)


代替的に、聞かせて、単一パスで同じことを行うから、左の任意の2点間のrealtionことQRで、Pように、qはの左側にあるR場合qは左側にあります通る直線のPおよびR。被左の上の順序関係であることに注意してくださいPは場合とにおける全ての点場合にのみPが通過するいくつかのラインの同じ側にあるP場合、であり、pはの凸包の外側にあるP。上記の手順は、Pの最小点を見つけますこの順序、つまりPの「左端」のポイントについて。2つのパスを実行する代わりに、最大(つまり、「最も右」のポイント)と最小のPのポイントを1つのパスで同じ順序で見つけ、最小値が左にあることを確認できます。最大、つまり効果的には、左端が推移的です。

これは、pPの凸包の外側にある場合にうまく機能します。この場合、左方向は実際には順序関係ですが、pが凸包の内側にある場合は壊れる可能性があります(たとえば、我々がポイントこのアルゴリズム実行した場合に起こるPは反時計回りを実行している正五角形の頂点、あり、そしてpは我々は、ポイントを選択します。その中心であるが、我々はわずかアルゴリズムを変更し、対応するために)QPを、と二分pqを通る線に沿ってP(つまり、Pqの周りで分割するwrt to-the-left-of。)これで、Pの「左部分」と「右部分」がそれぞれ半平面に含まれるようになりました。したがって、to-the-left-ofはそれぞれの順序関係になります。左部分の最小値と右部分の最大値を見つけ、上記のように比較します。もちろん、Pを物理的に2等分する必要はありません。1 つのパスで最小値と最大値を探すときに、Pの各点を単純に分類できます。

Python 2、194バイト

import sys
P=[eval(l.replace(*";,"))for l in sys.stdin]
x,y=P.pop(0)
C=lambda(a,b),(c,d):(a-x)*(d-y)-(b-y)*(c-x)>0
l=r=P[0]
for q in P:
 if C(P[0],q):l=q*C(l,q)or l
 elif C(q,r):r=q
print C(l,r)

あなたがあなたの解決策(少なくともPythonの解決策、Jがそれを行うことができるかどうか私には手掛かりがない)がSTDINから入力を受け取る可能性はありますか?ソリューションを平等な競争条件と比較する方が簡単だと思います。入力がすでにフォーマット済みの複素数または複素数の点であると仮定すると、ストレッチIMOになります。
Alexandre Halm

@AlexandreHalm完全なプログラムを追加しました。
Ell

ソリューションを言語ごとに1つの回答に分割する必要があります。
Mego

4

オクターブ、82 72バイト

d=dlmread(0,";");i=2:rows(d);~isna(glpk(i,[d(i,:)';~~i],[d(1,:)';1]))&&1

アイデアは、線形プログラムmin {c'x:Ax = b、e'x = 1、x> = 0}に解があるかどうかをチェックすることです。ここで、eはすべて1のベクトル、Aの列はの座標です。点群、bはテストポイント、cは任意です。つまり、bをAの列の凸の組み合わせとして表現しようとします。

スクリプトを実行するには、 octave -f script.m <input.dat


2

R、207バイト

d=read.csv(file("stdin"),F,";")
q=function(i,j,k)abs(det(as.matrix(cbind(d[c(i,j,k),],1))))
t=function(i,j,k)q(i,j,k)==q(1,i,j)+q(1,i,k)+q(1,j,k)
any(apply(combn(2:nrow(d),3),2,function(v)t(v[1],v[2],v[3])))

スクリプトはSTDINから入力を受け取りますRscript script.R < inputFile

N最後の点(最後の線apply(combn(...)からすべての三角形を生成し、t関数を使用して最初の点が三角形内にあるかどうかをチェックします。

tかどうかを判断するための領域メソッドを使用UしているABC:(書き込み(ABC)の面積についてはABCUであるABCIFF (ABC) == (ABU) + (ACU) + (BCU)。また、面積は行列式を使用して計算されます(Wolframの優れたデモについては、こちらを参照してください)。

この解決策は他の解決策よりも数値エラーを起こしやすいと思いますが、テストケースで機能します。


0

R、282バイト

d=read.csv(file("stdin"),F,";")
p=function(a,b)a[1]*b[1]+a[2]*b[2]
t=function(a,b,c){A=d[a,];
U=d[1,]-A
B=d[b,]-A
C=d[c,]-A
f=p(C,C)
g=p(B,C)
h=p(U,C)
i=p(B,B)
j=p(U,B)
k=f*i-g*g
u=i*h-g*j
v=f*j-g*h
min(u*k,v*k,k-u-v)>0}
any(apply(combn(2:nrow(d),3),2,function(v)t(v[1],v[2],v[3])))

スクリプトはSTDINから入力を受け取りますRscript script.R < inputFile

N最後の点(最後の線apply(combn(...)からすべての三角形を生成し、t関数を使用して最初の点が三角形内にあるかどうかをチェックします。

tかどうかを決定する重心方法使用しUているABC:(書き込みXYのためXYベクター)ので(AB,AC)(A、B、Cが配列されている縮退場合を除く)面の基礎であるが、AUのように書くことができるAU = u.AB + v.ACU三角形IFFでありますu > 0 && v > 0 && u+v < 1。詳細な説明とインタラクティブなグラフについては、たとえばこちらをご覧ください。NB:いくつかの文字と回避のDIV0エラーを節約するために、我々は唯一のショートカットを計算uしてv、変更のテストを(min(u*k,v*k,k-u-v)>0)。

使用される唯一の数学的な演算子は+-*min()>0

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