三角形の特定


11

写真の三角形の数を数えることは、脳のテストで一般的に使用されるタスクです。三角形で構成される図形を含む画像が表示されます。次に、画像内のすべての可能な三角形を見つける必要があります。

仕事

選択した形式の行のリストが表示されます。次に、その中にある三角形のリストを出力する必要があります

入力

行のリストが与えられ、各行は4つの整数座標(例:)で与えられx1 y1 x2 y2ます。明確に文書化されている限り、入力形式を選択できます。例:

0 4 8 1
0 4 9 5
8 1 9 5
2 8 0 4
9 5 2 8

[[0, 4, 8, 1], [0, 4, 9, 5], [8, 1, 9, 5], [2, 8, 0, 4], [9, 5, 2, 8]]

これは画像と同じ入力です:

三角形の描画

交差点を使用する別の1つ(スペースを節約するために1つの形式のみ):

[[2, 1, 5, 0], [2, 1, 2, 7], [5, 0, 6, 6], [5, 0, 2, 7], [6, 6, 2, 1], [2, 7, 6, 6]]

三角形の描画

出力

x1 y1 x2 y2 x3 y3入力で指定された画像に、6つの浮動小数点座標(例:)で指定されたすべての三角形のリストを出力する必要があります。線は任意の点で交差する可能性があるため、これらは整数ではない場合があります。明確に文書化されている限り、出力形式を選択できます。上記の入力例の出力例:

0 4 8 1 9 5
0 4 9 5 2 8

[[0, 4, 8, 3, 9, 5], [0, 4, 9, 5, 2, 8]]
[[2, 1, 5, 0, 2, 7], [2, 1, 5, 0, 6, 6], [5, 0, 6, 6, 2, 7], [2, 1, 6, 6, 2, 7], [2, 1, 5, 0, 3.674, 3.093], [5, 0, 6, 6, 3.674, 3.093], [6, 6, 2, 7, 3.674, 3.093], [2, 7, 2, 1, 3.674, 3.093]]

あなたはそれを仮定するかもしれません

  • 線が交差点を横切るが、線を横切るエッジケースはありません。

    [[0, 9, 1, 8], [1, 8, 2, 9], [2, 9, 3, 8], [3, 8, 4, 9], [4, 9, 0, 9]]
    
  • 179度以上の角度はありません

    [[0, 0, 0, 1], [0, 1, 0, 2], [0, 2, 0, 0]]
    

ルール

  • 任意の言語を使用できます。
  • 外部リソースを使用する必要はありません。
  • 標準の抜け穴が適用されます。

得点

これはであるため、バイト単位の最短回答が優先さます


3サイクルを特定するだけで十分ですか、それともより複雑なエッジケースを処理する必要がありますか?たとえば、によって定義される「五角形」[0,9],[1,8],[2,9],[3,8],[4,9]は、実際には上部に線が引かれたWです。三角形がないのですか、それとも2つの三角形ですか?
レベルリバーセント

@steveverrillエッジケースは無視できるとしましょう。
PurkkaKoodari

OK。そして[0,0],[1,0],[2,0],[1,2]、180度の1つの角度を持つ「四辺形」。三角形なしまたは1つの三角形ですか?
レベルリバーセント

それは三角形ではないでしょうが、あなたもそれが来ないと仮定するかもしれません。
PurkkaKoodari

回答:


1

PostGIS、162

これはルールに準拠していると思います。PostgreSQLの拡張機能であるPostGISのクエリです。入力は、Lと呼ばれる各ラインの座標のテーブルであると想定されます。出力は、形成された三角形のポリゴン定義を持つ行のセットです。

SELECT ST_AsText(D)FROM(SELECT(ST_Dump(ST_Polygonize(B))).geom D FROM(SELECT ST_Union(ST_MakeLine(ST_Point(A,B),ST_Point(C,D)))B FROM L)A)B WHERE ST_NPoints(D)=4;

使用中は次のようになります

-- Create a table for the input
CREATE TABLE L (A INT, B INT, C INT,D INT);
INSERT INTO L VALUES(2, 1, 5, 0), (2, 1, 2, 7), (5, 0, 6, 6), (5, 0, 2, 7), (6, 6, 2, 1), (2, 7, 6, 6);

SELECT ST_AsText(D)FROM(SELECT(ST_Dump(ST_Polygonize(B))).geom D FROM(SELECT ST_Union(ST_MakeLine(ST_Point(A,B),ST_Point(C,D)))B FROM L)A)B WHERE ST_NPoints(D)=4;

-- Cleanup
DROP TABLE L;

出力は次のとおりです

POLYGON((5 0,2 1,3.67441860465116 3.09302325581395,5 0))
POLYGON((6 6,5 0,3.67441860465116 3.09302325581395,6 6))
POLYGON((3.67441860465116 3.09302325581395,2 7,6 6,3.67441860465116 3.09302325581395))
POLYGON((2 7,3.67441860465116 3.09302325581395,2 1,2 7))

7

Mathematica 915 395 401 405

更新

このプログラミングの課題は、最初に思われるよりもはるかに困難です。

現在のアプローチは、任意のラインセグメントの長さに沿って交差点が1つしかない単純なケースで機能します。1つのセグメントに沿って複数の交差点がある場合、各線に沿ったすべての交差点を追跡し、新しいサブセグメントを作成して(グラフのエッジを追加)、新しい交差点をターゲットラインに沿ったすべての交差点に接続する必要があります。

その制限にもかかわらず、現在のアプローチの基礎となるロジックを共有する価値があるかもしれません。


入力線分は領域として扱われます。それらが交差する場合、重心は交差点の座標になります。ラインセグメントの頂点で発生する交差を削除する必要があります。交差しない線には、不確定な重心があります。

交差点ごとに4つの新しいエッジが作成されます。交差点を、交差する2本の線の4つの頂点に接続します。

下の右側のようなグラフは、古いエッジと新しいエッジの両方を使用して生成されます。

頂点は、それぞれのポイントの座標です。3つの頂点が同一直線上にない場合、サイクル、つまり3つの頂点の閉ループは三角形になります。

現在、「三角形」に不確定な領域があるかどうかを確認します。(何らかの理由で、3つの同一直線上のポイントに対して0の面積を返しません。)


簡単な例

以下は、(a)座標平面にプロットされた図と、(b)与えられたノードと交差点ノードを示すグラフ{114/23, 314/69}です。後者では、頂点はそれぞれのデカルト座標にありません。

左側よりも右側の図の方がエッジが多いように見える場合があります。ただし、左側にグラフのエッジが重なっていることに注意してください。各対角線は実際には3つのグラフエッジに対応しています!


グラフ

    f@w_ :=(h@{a_, b_, c_, d_} := (r = RegionCentroid@RegionIntersection[Line@{a, b}, Line@{c, d}];
     {r <-> a, r <-> b, r <-> c, r <-> d});
      Cases[FindCycle[Graph[Union@Join[w /. {{a_, b_Integer}, {c_, d_}} :> {a, b} <-> {c, d},
      Cases[Flatten[h /@ Cases[{Length[Union@#] < 4, #} & /@ (FlattenAt[#, {{1}, {2}}] & /@ 
      Subsets[w, {2}]),{False, c_} :> c]], Except[{Indeterminate, _} <-> _]]]], {3}, 50],
      x_ /; NumericQ[RegionMeasure@Triangle[x[[All, 1]]]]][[All, All, 1]]//N//Grid)

以下の各行は三角形です。

f[{{{2,8},{8,1}},{{0,4},{8,1}},{{0,4},{9,5}},{{8,1},{9,5}},{{2,8},{0,4}},{{9,5},{2,8}}}]

座標


より複雑な例

f@{{{9, 5}, {0, -10}}, {{9, 5}, {0, 2}},  {{9, 5}, {2, -1}}, {{0, -10}, {2, -1}}, {{0, -10}, {-2, -1}}, {{-9, 5}, {0, -10}}, {{-9, 5}, {0, 2}}, {{-9, 5}, {-2, -1}}, {{0, 2}, {0, -10}}, {{-9, 5}, {2, -1}}, {{9, 5}, {-2, -1}}, {{-9, 5}, {9, 5}}}

入力座標に対応するグラフは次のとおりです。頂点は予想されるデカルト座標にあります。(ゴルフのコードを実行すると、頂点のラベルとエッジを尊重しながら他の場所に頂点が表示されます。読みやすくするために、ソリューションに不要な追加のコードを使用して頂点座標を割り当てました。)

graph2


これが派生グラフです。入力線の一部が
交差する派生交差点が含まれます(0,1/11)

19

コードは19個の三角形を見つけました。それらの9 (0,1/11)つが頂点の1つとしてポイントを持っています。

nineteen2


OK。現在は関数の形式になっています。
DavidC

4

Java、1051 1004

(完全に機能するプログラム)

これは、いくつかのコードをゴルフするだけでなく、主に数学関数の作成を練習するという素晴らしい挑戦だと思いました。

そして、「ベースライン」を描くために、私はこれをJavaで作成しました*みんなが笑い始めるのを待ちます*

コード

import java.util.*;class P{double x,y;static P l(double... i){double a=i[0],b=i[1],c=i[2],d=i[3],e=i[4],f=i[5],k,l,x=(k=i[7]-f)*(c-a)-(l=i[6]-e)*(d-b),n=(l*(b-f)-k*(a-e))/x,m=((c-a)*(b-f)-(d-b)*(a-e))/x;P p=new P();p.x=a+n*(c-a);p.y=b+n*(d-b);return(n>=0&n<=1&m>=0&m<=1&x!=0)?p:null;}public static void main(String[]p){Set<String>v=new HashSet();P q,w,e;Integer a,b,c,d,k,f,g,h,i,j,m,l,r,t,y,z;int[][]x=new int[l=p.length/4][4];for(c=0;c<l;c++){for(d=0;d<4;){x[c][d]=l.parseInt(p[c*4+d++]);}}z=x.length;for(r=0;r<z;r++){a=x[r][0];b=x[r][1];c=x[r][2];d=x[r][3];for(t=0;t<z;t++){if(t!=r){k=x[t][0];f=x[t][1];g=x[t][2];h=x[t][3];q=l(a,b,c,d,k,f,g,h);if(q!=null){for(y=0;y<z;y++){if(y!=r&y!=t){i=x[y][0];j=x[y][1];m=x[y][2];l=x[y][3];w=l(a,b,c,d,i,j,m,l);e=l(k,f,g,h,i,j,m,l);if(w!=null&&e!=null&&q.x!=e.x&q.y!=e.y&!v.contains(""+r+y+t)){v.add(""+r+t+y);v.add(""+r+y+t);v.add(""+t+r+y);v.add(""+t+y+r);v.add(""+y+r+t);v.add(""+y+t+r);System.out.printf("%s %s %s %s %s %s\n",q.x,q.y,w.x,w.y,e.x,e.y);}}}}}}}}}

入力

スペースで区切られた整数。4つのペア(x​​1、y1、x2、y2)

2 1 5 0 2 1 2 7 5 0 6 6 5 0 2 7 6 6 2 1 2 7 6 6

出力(実際の出力は小数点以下3桁に丸められません)

各行には1つの三角形が含まれます。各行は、スペースで区切られた2つのペアの浮動小数点で構成されます(x1、y1、x2、y2、x3、y3)。(注:三角形を形成する3点の順序は定義されていません。)

5.0 0.0 2.0 1.0 6.0 6.0
5.0 0.0 2.0 1.0 2.0 7.0
5.0 0.0 2.0 1.0 3.674 3.093
2.0 7.0 2.0 1.0 3.674 3.093
2.0 1.0 2.0 7.0 6.0 6.0
5.0 0.0 6.0 6.0 3.674 3.093
5.0 0.0 6.0 6.0 2.0 7.0
3.674 3.093 2.0 7.0 6.0 6.0

説明

私は、2つの無限ではない線の交差点を見つける方法を書き始めました。結果のメソッドは、Javaスタイル用のもので、かなり短いものです(246)。メソッド入力を8ダブルまたは2ポイント(P)で構成する代わりに、大量の文字を安全に保護するために任意のパラメーターを使用することを選択します。配列演算子の使用を最小限に抑えるために、2回以上使用される各パラメーターは独自の変数に配置されます。

static P l(double... i){double a=i[0],b=i[1],c=i[2],d=i[3],e=i[4],f=i[5],k,l,x=(k=i[7]-f)*(c-a)-(l=i[6]-e)*(d-b),n=(l*(b-f)-k*(a-e))/x,m=((c-a)*(b-f)-(d-b)*(a-e))/x;P p=new P();p.x=a+n*(c-a);p.y=b+n*(d-b);return(n>=0&n<=1&m>=0&m<=1&x!=0)?p:null;}

さらに説明を追加します...(おそらく、この答えはさらに詳しく説明されています)


0

BBC BASIC

http://www.bbcbasic.co.uk/bbcwin/bbcwin.htmlのエミュレーター

私はこれが400年代までゴルフをすることを期待しています。

入出力

ユーザーが新しい行を入力するたびに、プログラムは新しい三角形が作成されたかどうかを確認し、すぐに出力します。以下を参照してください。

新しいラインが相互に交差する既存の2本のラインと交差する場所に新しい三角形が作成されます(3つのラインすべてがポイントで交差する場合を除きます。これは特別な場合です)。

ここに画像の説明を入力してください

コード

メインプログラムはできる限りシンプルです。最後に、http://en.wikipedia.org/wiki/Line%E2%80%93line_intersectionの式に従って、交差を検出する複雑なタスクを実行する関数があります

この関数は、交差がない場合はゼロを返し、存在する場合はゼロ以外の浮動小数点数を返します。また、副作用もあります。交差点の座標が文字列z $に追加されます。さらに、BBC Basicでは、メインプログラムに同じ名前の変数がない場合(関数が終了した後でも)、関数の変数はメインプログラムに表示されます。

したがって、メインプログラムは変数にアクセス有しxy、及びmn現在と以前の交点の座標を格納します。これは、ある点で交差する3本の線だけでなく、実際に三角形を見つけたかどうかを検出するために使用されます。

  DIM a(99),b(99),c(99),d(99)                                                    :REM declare 4 arrays to hold the ata
  y=0                                                                            :REM x and y are only initialized
  x=0                                                                            :REM to avoid a no such varialbe error later
  FOR i=0 TO 99                                                                  :REM for each input line
    INPUT a(i),b(i),c(i),d(i)
    FOR j=0 TO i-1                                                               :REM iterate through all combinations of 2 previous lines
      FOR k=0 TO j-1
        z$=""                                                                    :REM clear z$, three function calls on next line will write the triangle (if found) to it
        IF i>j AND j>k AND FNf(i,j)*FNf(i,k)*FNf(j,k)<>0 IF x<>m OR y<>n PRINT z$:REM to avoid printing the same triangle twice, print only if j,k,i in lexicographic order. Also reject if x,y (3rd FNf call) and m,n (2nd FNf call) are the same: this means a point, not a triangle.
      NEXT
    NEXT
  NEXT

  DEF FNf(g,h)                                                                   :REM returns zero if no intersection found, otherwise a floating point value
  m=x                                                                            :REM backup previous x and y
  n=y                                                                            :REM to use in test for point versus triangle
  p=a(g)-c(g)
  q=b(g)-d(g)
  r=a(h)-c(h)
  s=b(h)-d(h)
  t=a(g)*d(g)-b(g)*c(g)
  u=a(h)*d(h)-b(h)*c(h)
  e=p*s-q*r                                                                      :REM following method in wikipedia, calculate denominator of expression
  IF e<>0 x=(t*r-u*p)/e : y=(t*s-u*q)/e: z$=z$+" "+STR$(x)+" "+STR$(y)           :REM if denominator not zero, calculate x and y and append a string copy to z$
  IF (a(g)-x)*(c(g)-x)>0 OR (b(g)-y)*(d(g)-x)>0 OR(a(h)-x)*(c(h)-x)>0 OR(b(h)-y)*(d(h)-y)>0 e=0
  =e          :REM return e                                                      :REM previous line sets e to zero if the intersection falls outside the line segment. This is detected when both are on the same side of the intersection, which yields a positive multiplication result.
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.