Xác định các hình tam giác


11

Đếm số lượng hình tam giác trong một bức tranh là một nhiệm vụ thường được sử dụng trong các bài kiểm tra não. Bạn được cung cấp một hình ảnh có chứa hình dạng bao gồm các hình tam giác. Sau đó, bạn phải tìm tất cả các hình tam giác có thể trong hình.

Bài tập

Bạn được cung cấp một danh sách các dòng trong một định dạng của sự lựa chọn của bạn. Sau đó, bạn phải xuất ra một danh sách các hình tam giác được tìm thấy trong đó

Đầu vào

Bạn được cung cấp một danh sách các dòng, mỗi dòng được cho bởi bốn tọa độ nguyên (ví dụ. x1 y1 x2 y2). Bạn có thể chọn định dạng đầu vào, miễn là nó được ghi lại rõ ràng. Ví dụ:

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]]

Đây là đầu vào giống như một hình ảnh:

vẽ tam giác

Một số khác, với các giao điểm (chỉ trong một định dạng để tiết kiệm không gian):

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

vẽ tam giác

Đầu ra

Bạn phải xuất ra một danh sách tất cả các hình tam giác, mỗi hình được cho bởi sáu tọa độ dấu phẩy động (ví dụ x1 y1 x2 y2 x3 y3), trong hình được chỉ định bởi đầu vào. Đây có thể không phải là số nguyên, vì các dòng có thể giao nhau tại bất kỳ điểm nào. Bạn có thể chọn định dạng đầu ra, miễn là nó được ghi lại rõ ràng. Ví dụ đầu ra cho các đầu vào ví dụ ở trên:

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]]

Bạn có thể cho rằng

  • không có trường hợp cạnh nào mà đường thẳng đi qua giao lộ nhưng không có đường nào, như

    [[0, 9, 1, 8], [1, 8, 2, 9], [2, 9, 3, 8], [3, 8, 4, 9], [4, 9, 0, 9]]
    
  • không có góc trên 179 độ, như

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

Quy tắc

  • Bạn có thể sử dụng bất kỳ ngôn ngữ nào bạn muốn.
  • Không có tài nguyên bên ngoài phải được sử dụng.
  • Tiêu chuẩn áp dụng.

Chấm điểm

Đây là , vì vậy câu trả lời ngắn nhất bằng byte sẽ thắng.


Là nó đủ để xác định 3 chu kỳ hay chúng ta phải xử lý các trường hợp cạnh phức tạp hơn? Ví dụ: "ngũ giác" được xác định bởi [0,9],[1,8],[2,9],[3,8],[4,9]thực sự là một W với một đường được vẽ trên đầu. Có phải đó không phải là tam giác hay 2 tam giác?
Cấp sông St

@steveverrill Hãy nói rằng các trường hợp cạnh có thể bị bỏ qua.
PurkkaKoodari

Đồng ý. Và [0,0],[1,0],[2,0],[1,2]một "tứ giác" với một góc 180 độ. Không có tam giác hay 1 tam giác?
Cấp sông St

Đó sẽ không phải là một hình tam giác, nhưng bạn có thể cho rằng điều đó cũng không xảy ra.
PurkkaKoodari

Câu trả lời:


1

PostGIS, 162

Tôi nghĩ rằng điều này tuân thủ các quy tắc, Đó là một truy vấn cho PostGIS, một phần mở rộng của PostgreQuery. Đầu vào được giả sử là một bảng tọa độ cho mỗi dòng được gọi là L Đầu ra là một tập hợp các hàng với định nghĩa đa giác cho các tam giác được hình thành.

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;

Trong sử dụng có vẻ như sau

-- 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;

Đầu ra như sau

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

Toán học 915 395 401 405

Cập nhật

Thử thách lập trình này khó khăn hơn nhiều so với lần đầu tiên xuất hiện.

Cách tiếp cận hiện tại hoạt động với các trường hợp đơn giản, trong đó có một giao điểm duy nhất dọc theo chiều dài của bất kỳ đoạn đường nào. Với nhiều giao cắt dọc theo một đoạn, cần theo dõi tất cả các điểm giao nhau dọc theo mỗi đường và tạo các phân đoạn mới (do đó các cạnh biểu đồ bổ sung) kết nối giao lộ mới với tất cả các điểm giao nhau dọc theo đường đích.

Mặc dù hạn chế đó, có thể đáng để chia sẻ logic theo cách tiếp cận hiện tại.


Các phân đoạn dòng đầu vào được coi là khu vực. Nếu chúng giao nhau, tâm sẽ là tọa độ của giao. Chúng ta cần loại bỏ các giao điểm xảy ra ở các đỉnh của các đoạn thẳng. Các đường không giao nhau sẽ có trọng tâm không xác định.

Bốn cạnh mới được tạo cho mỗi điểm giao nhau. Chúng kết nối điểm giao nhau với bốn đỉnh của hai đường giao nhau.

Một biểu đồ như hình bên dưới bên phải được tạo bằng cả cạnh cũ và cạnh mới.

Các đỉnh là tọa độ của các điểm tương ứng. Chu kỳ, tức là các vòng khép kín của ba đỉnh sẽ là các hình tam giác với điều kiện là ba đỉnh không thẳng hàng.

Hiện tại chúng tôi kiểm tra xem liệu bất kỳ "tam giác" nào có diện tích không xác định. (Vì một số lý do, nó không trả về diện tích 0 cho ba điểm cộng tuyến.)


Một ví dụ đơn giản

Dưới đây là (a) hình vẽ trong mặt phẳng tọa độ và (b) biểu đồ hiển thị các nút đã cho cũng như nút giao nhau , {114/23, 314/69}. Trong phần sau, các đỉnh không nằm ở tọa độ Descartes tương ứng.

Có vẻ như chúng có nhiều cạnh trong hình bên phải hơn bên trái. Nhưng hãy nhớ rằng có các cạnh đồ thị chồng lên nhau ở bên trái. Mỗi đường chéo thực sự tương ứng với 3 cạnh đồ thị!


đồ thị

    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)

Mỗi hàng bên dưới là một hình tam giác.

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}}}]

coords


Một ví dụ phức tạp hơn

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}}}

Đây là biểu đồ tương ứng với tọa độ đầu vào . Các đỉnh nằm ở tọa độ Descartes dự kiến ​​của chúng. (Nếu bạn chạy mã được đánh gôn, nó sẽ hiển thị các đỉnh ở nơi khác trong khi tôn trọng các nhãn và các cạnh của đỉnh.

đồ thị2


Đây là biểu đồ dẫn xuất.
Nó bao gồm điểm xuất phát của giao lộ (0,1/11), nơi một số dòng đầu vào giao nhau.

mười chín

Mã tìm thấy 19 hình tam giác. Chín trong số chúng có điểm, (0,1/11)là một trong những đỉnh.

mười chín


Đồng ý. Bây giờ nó ở dạng của một chức năng.
DavidC

4

Java, 1051 1004

(Chương trình hoàn toàn hoạt động)

Tôi nghĩ rằng đây là một thử thách thú vị không chỉ để đánh gôn, mà chủ yếu là thực hành viết các hàm toán học.

Và để vẽ một "đường cơ sở" tôi đã tạo cái này bằng Java * Chờ mọi người bắt đầu cười * .

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);}}}}}}}}}

Đầu vào

Không gian cách nhau số nguyên. Theo cặp 4 (x1, 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

Đầu ra (đầu ra thực không làm tròn đến 3 số thập phân)

Mỗi dòng chứa một tam giác Mỗi dòng bao gồm các điểm nổi cách nhau trong không gian theo cặp 2 (x1, y1, x2, y2, x3, y3). (Lưu ý: thứ tự của 3 điểm tạo thành tam giác là không xác định.)

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

Giải trình

Tôi bắt đầu viết một phương pháp để tìm giao điểm giữa hai dòng không vô hạn. Phương thức kết quả dành cho kiểu Java khá ngắn (246). Thay vì để đầu vào phương thức bao gồm 8 nhân đôi hoặc hai Điểm (P), tôi chọn sử dụng tham số tùy ý để đảm bảo số lượng lớn ký tự. Để giảm thiểu việc sử dụng toán tử mảng, mỗi tham số được sử dụng nhiều hơn 2 lần được đặt trong biến riêng của nó.

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;}

Thêm lời giải thích được thêm vào ... (câu trả lời này có thể được đánh gôn nhiều hơn)


0

BBC CƠ BẢN

Trình giả lập tại http://www.bbcbasic.co.uk/bbcwin/bbcwin.html

Tôi đang mong đợi điều này để chơi golf vào những năm 400.

Đầu ra đầu vào

Mỗi khi người dùng nhập một dòng mới, chương trình sẽ kiểm tra xem có bất kỳ hình tam giác mới nào được tạo không, và xuất ra chúng ngay lập tức, xem bên dưới.

Một tam giác mới được tạo ra ở bất cứ nơi nào đường mới giao nhau với hai đường có sẵn cũng giao nhau (trừ khi cả ba đường thẳng giao nhau tại một điểm, đó là trường hợp đặc biệt phải xử lý.)

nhập mô tả hình ảnh ở đây

Chương trình chính là đơn giản như có thể. Cuối cùng là chức năng, thực hiện nhiệm vụ phức tạp là phát hiện các giao lộ, theo công thức trong http://en.wikipedia.org/wiki/Line%E2%80%93line_intersection

Hàm trả về 0 nếu không có giao điểm và số dấu phẩy động khác không nếu có. Nó cũng có tác dụng phụ: tọa độ của giao điểm được gắn vào chuỗi z $. Ngoài ra, trong cơ bản BBC, các biến của hàm được hiển thị cho chương trình chính với điều kiện chương trình chính không có biến cùng tên (ngay cả khi hàm đã kết thúc.)

Do đó, chương trình chính có quyền truy cập vào các biến xy, mn, nơi lưu trữ tọa độ của các giao điểm hiện tại và trước đó. Điều này được sử dụng để phát hiện nếu chúng ta thực sự tìm thấy một hình tam giác và không chỉ ba đường thẳng giao nhau tại một điểm.

  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.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.