Визначення трикутників


11

Підрахунок кількості трикутників на малюнку - це завдання, яке зазвичай використовується в тестах мозку. Вам дають малюнок, який містить фігури, що складаються з трикутників. Потім ви повинні знайти всі можливі трикутники на малюнку.

Завдання

Вам надається список рядків у обраному вами форматі. Потім потрібно вивести список трикутників, знайдених у цьому

Вхідні дані

Вам надається список рядків, кожен із яких задається чотирма цілими координатами (наприклад, 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]]

Ось такий самий вхід, як і зображення:

трикутник малювання

Ще один із перехрестями (лише в одному форматі для економії місця):

[[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) на зображенні, визначеному вхідним сигналом. Це можуть бути не цілі числа, оскільки рядки можуть перетинатися в будь-якій точці. Ви можете вибрати вихідний формат, якщо він чітко зафіксований. Приклади виходів для наведених вище прикладів:

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

Гаразд. І А [0,0],[1,0],[2,0],[1,2]"чотирикутник" з одним кутом 180 градусів. Немає трикутників чи 1 трикутника?
Рівень р. Св.

Це не був би трикутник, але ви можете припустити, що і те не відбувається.
PurkkaKoodari

Відповіді:


1

PostGIS, 162

Я думаю, що це відповідає правилам. Це запит на PostGIS, який є розширенням PostgreSQL. Вхідним вважається таблиця координат для кожного рядка під назвою 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

Оновлення

Цей виклик програмування набагато складніше, ніж спочатку здається.

Цей підхід працює з простими випадками, коли існує лише одне перетин по довжині будь-якого відрізка лінії. Маючи декілька перетинів уздовж одного відрізка, необхідно відслідковувати всі точки перетину уздовж кожної лінії та створювати нові підсегменти (отже, додаткові краї графіка), що з'єднують новий перетин з усіма точками перетину уздовж цільової лінії.

Незважаючи на це обмеження, можливо, варто поділитися логікою, що лежить в основі поточного підходу.


Сегменти вхідних рядків розглядаються як регіони. Якщо вони перетинаються, центроїд буде координатами перетину. Нам потрібно усунути ті перетини, які виникають у вершинах відрізків ліній. Лінії, які не перетинаються, матимуть невизначений центроїд.

Для кожної точки перетину створюються чотири нові ребра. Вони з'єднують точку перетину з чотирма вершинами двох прямих, що перетинаються.

Такий графік, як той, що знаходиться праворуч, генерується за допомогою старого та нового ребер.

Вершини - це координати відповідних точок. Цикли, тобто замкнуті петлі з трьох вершин будуть трикутниками за умови, що три вершини не є колінеарними.

Зараз ми перевіряємо, чи має якийсь "трикутник" невизначену площу. (Чомусь він не повертає площу 0 для трьох колінеарних точок.)


Простий приклад

Нижче (а) фігура зображена на координатної площині і (б) графік , який показує дані вузли, а також вузол перетину, {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}}}

Ось графік, відповідний вхідним координатам. Вершини знаходяться в очікуваних декартових координатах. (Якщо ви запускаєте код golfed, він відображатиме вершини в іншому місці, дотримуючись міток і країв вершин. Для читабельності я призначив координати вершин за допомогою додаткового коду, не потрібного для рішення.)

графік2


Ось отриманий графік.
Він включає похідну точку перетину (0,1/11), де перетинаються деякі вхідні лінії.

дев’ятнадцять

У коді знайдено 19 трикутників. Дев'ять з них мають крапку, (0,1/11)як одну з вершин.

дев’ятнадцять2


Гаразд. Зараз це у формі функції.
DavidC

4

Ява, 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 (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

Вихід (реальний вихід не округлює до 3 десяткових знаків)

Кожен рядок містить один трикутник. Кожен рядок складається з плаваючих точок, розділених простором, парами по 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

Пояснення

Я почав писати метод пошуку перетину між двома нескінченними лініями. Отриманий метод для стилю Java один досить короткий (246). Замість того, щоб дозволити введення методу складається з 8 подвійних або двох точок (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-х.

Введення-виведення

Кожен раз, коли користувач вводить новий рядок, програма перевіряє, чи були створені якісь нові трикутники, і виводить їх негайно, див. Нижче.

Новий трикутник створюється там, де нова лінія перетинається з двома попередньо існуючими лініями, які також взаємно перетинаються (за винятком випадків, коли всі три лінії перетинаються в точці, що є особливим випадком, з яким потрібно мати справу.)

введіть тут опис зображення

Код

Основна програма настільки ж проста, наскільки це можливо. В кінці - функція, яка виконує складне завдання виявлення перехресть, за формулою в http://en.wikipedia.org/wiki/Line%E2%80%93line_intersection

Функція повертає нуль, якщо немає перетину, і ненульове число з плаваючою точкою, якщо є. Він також має побічний ефект: координати перетину додаються до рядка z $. Крім того, у базовій програмі BBC змінні функції є видимими для основної програми за умови, що основна програма не має однойменної змінної (навіть після закінчення функції.)

Тому основна програма має доступ до змінних xта y, та mі n, які зберігають координати поточного та попереднього перетинів. Це використовується для виявлення, чи дійсно ми знайшли трикутник, а не лише три лінії, що перетинаються в точці.

  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.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.