Üçgenleri belirleme


11

Bir resimdeki üçgen miktarını saymak beyin testlerinde yaygın olarak kullanılan bir görevdir. Size üçgenlerden oluşan şekiller içeren bir resim verilir. Ardından resimdeki tüm üçgenleri bulmalısınız.

Görev

Seçtiğiniz biçimde bir satır listesi verilir. Daha sonra, içinde bulunan üçgenlerin bir listesini çıkarmalısınız.

Giriş

Size her biri dört tamsayı koordinatı (örn. x1 y1 x2 y2) İle verilen bir satır listesi verilir . Açıkça belgelendiği sürece giriş biçimini seçebilirsiniz. Örnekler:

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

İşte görüntü ile aynı girdi:

üçgen çizimi

Bir diğeri, kavşaklarla (yerden tasarruf etmek için sadece bir biçimde):

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

üçgen çizimi

Çıktı

Her biri x1 y1 x2 y2 x3 y3giriş tarafından belirtilen resimde altı kayan nokta koordinatı (örn. ) İle verilen tüm üçgenlerin bir listesini çıkarmalısınız. Çizgiler herhangi bir noktada kesilebileceği için bunlar tamsayı olmayabilir. Açıkça belgelendiği sürece çıktı biçimini seçebilirsiniz. Yukarıdaki örnek girişler için örnek çıktılar:

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

Bunu varsayabilirsin

  • bir çizginin kesişme noktasını geçtiği kenar durumlar yoktur, ancak

    [[0, 9, 1, 8], [1, 8, 2, 9], [2, 9, 3, 8], [3, 8, 4, 9], [4, 9, 0, 9]]
    
  • 179 derecenin üzerinde açı yok, mesela

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

kurallar

  • İstediğiniz dili kullanabilirsiniz.
  • Hiçbir harici kaynak kullanılmamalıdır.
  • Standart boşluklar geçerlidir.

puanlama

Bu kadar kısa cevap, bayt kazanır.


3 döngüyü tanımlamak yeterli mi yoksa daha karmaşık kenar vakalarını ele almamız mı gerekiyor? Örneğin, tarafından tanımlanan "beşgen" [0,9],[1,8],[2,9],[3,8],[4,9]aslında üstte bir çizgi bulunan bir W'dir. Üçgen mi yoksa 2 üçgen mi?
Level River St

@steveverrill Diyelim ki kenar vakalar göz ardı edilebilir.
PurkkaKoodari

Tamam. Ve Ve [0,0],[1,0],[2,0],[1,2]180 derecelik bir açı ile bir "dörtgen". Üçgen veya 1 üçgen yok mu?
Level River St

Bu bir üçgen olmaz, ama bunun da gelmediğini varsayabilirsiniz.
PurkkaKoodari

Yanıtlar:


1

PostGIS, 162

Bu kurallara uygun olduğunu düşünüyorum, PostgreSQL bir uzantısı olan PostGIS için bir sorgu. Girdinin, L olarak adlandırılan her satır için bir koordinat tablosu olduğu varsayılır. Çıktı, oluşturulan üçgenler için çokgen tanımına sahip bir satır kümesidir.

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;

Kullanımda aşağıdaki gibi görünüyor

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

Çıktı aşağıdaki gibidir

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

Güncelleme

Bu programlama zorluğu ilk göründüğünden çok daha zor.

Mevcut yaklaşım, herhangi bir çizgi parçasının uzunluğu boyunca tek bir kesişmenin olduğu basit durumlarla çalışır. Bir segment boyunca birden fazla geçişle, her bir çizgi boyunca tüm kesişim noktalarını takip etmek ve yeni kesiti hedef çizgisi boyunca tüm kesişim noktalarına bağlayan yeni alt segmentler (dolayısıyla ek grafik kenarları) oluşturmak gerekir.

Bu sınırlamaya rağmen, mevcut yaklaşımın altında yatan mantığı paylaşmaya değer olabilir.


Giriş hattı segmentleri bölge olarak kabul edilir. Kesişirlerse, sentroid kesişimin koordinatları olacaktır. Çizgi parçalarının köşelerinde meydana gelen kavşakları ortadan kaldırmalıyız. Kesişmeyen çizgiler belirsiz bir merkeze sahip olacaktır.

Her kesişme noktası için dört yeni kenar oluşturulur. Kesişme noktasını iki kesişen çizginin dört köşesine bağlarlar.

Hem eski hem de yeni kenarlar kullanılarak sağdaki aşağıdaki gibi bir grafik oluşturulur.

Köşeler ilgili noktaların koordinatlarıdır. Döngüler, yani üç köşenin kapalı döngüleri, üç köşenin eşdoğrusal olmaması şartıyla üçgenler olacaktır.

Şu anda herhangi bir "üçgen" in belirsiz bir alanı olup olmadığını kontrol ediyoruz. (Bazı nedenlerden dolayı, üç eş doğrusal nokta için 0 alanı döndürmez.)


Basit bir örnek

Aşağıda düzlem koordinat ve grafiksel olarak, (a) Şekil (b) belirli bir düğüm olarak kesişim düğüm gösteren bir grafiktir {114/23, 314/69}. İkincisinde, köşeler ilgili Kartezyen koordinatlarında bulunmaz.

Bunların sağdaki resimde soldan daha fazla kenar olduğu görülebilir. Ancak, solda çakışan grafik kenarları olduğunu unutmayın. Her köşegen aslında 3 grafik kenarına karşılık gelir!


grafikleri

    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)

Aşağıdaki her satır bir üçgendir.

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


Daha karmaşık bir örnek

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

İşte giriş koordinatlarına karşılık gelen grafik . Köşeler beklenen Kartezyen koordinatlarındadır. (Golf kodunu çalıştırırsanız, köşe etiketlerine ve kenarlarına saygı gösterirken köşeleri başka bir yerde görüntüleyecektir. Okunabilirlik için, köşe kodlarını çözüm için gerekli olmayan bir ek kod dağılması kullanarak atadım.)

grafik2


İşte türetilmiş grafik. Bazı giriş çizgilerinin
kesiştiği türetilmiş kesişim noktasını içerir (0,1/11).

on dokuz

Kod 19 üçgen buldu. Bunlardan dokuzu (0,1/11)köşe noktalarından biri olarak düşünüyor.

nineteen2


Tamam. Şimdi bir işlev biçimindedir.
DavidC

4

Java, 1051 1004

(Tamamen çalışan bir program)

Bunun sadece bazı kodları golf oynamak için değil, aynı zamanda matematiksel fonksiyonlar yazmak için de güzel bir meydan okuma olduğunu düşündüm.

Ve bir "taban çizgisi" çizmek için bunu Java'da yaptım * Herkesin gülmeye başlamasını bekler * .

kod

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

Giriş

Boşluk ile ayrılmış tamsayılar. 4 çift halinde (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

Çıktı (gerçek çıktı 3 ondalığa yuvarlanmaz)

Her çizgi bir üçgen içerir Her çizgi, 2 çift (x1, y1, x2, y2, x3, y3) olarak boşlukla ayrılmış kayan noktalardan oluşur. (Not: üçgeni oluşturan 3 noktanın sırası tanımlanmamıştır.)

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

açıklama

Sonsuz olmayan iki çizgi arasındaki kesişmeyi bulmak için bir yöntem yazmaya başladım. Ortaya çıkan yöntem bir Java tarzı oldukça kısa (246) içindir. Yöntem girdisinin 8 çift veya iki Noktadan (P) oluşmasına izin vermek yerine, büyük miktarlardaki karakterleri güvenli hale getirmek için rastgele bir parametre kullanmayı seçiyorum. Dizi operatörü kullanımını en aza indirmek için, 2 kattan fazla kullanılan her parametre kendi değişkenine yerleştirilir.

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

Eklenecek daha fazla açıklama ... (bu cevap muhtemelen daha da golf edilebilir)


0

BBC TEMEL

Http://www.bbcbasic.co.uk/bbcwin/bbcwin.html adresindeki emülatör

400'lü yıllara kadar golf oynamak için bekliyorum.

Giriş çıkış

Kullanıcı her yeni satıra girdiğinde, program herhangi bir yeni üçgen oluşturulup oluşturulmadığını kontrol eder ve hemen çıktı verir, aşağıya bakınız.

Yeni çizginin, karşılıklı olarak kesişen önceden var olan iki çizgiyle kesiştiği her yerde yeni bir üçgen oluşturulur (üç çizginin de bir noktada kesişmesi dışında, ele alınması gereken özel bir durumdur).

resim açıklamasını buraya girin

kod

Ana program olabildiğince basit. Sonunda, http://en.wikipedia.org/wiki/Line%E2%80%93line_intersection içindeki formüle göre, kavşakları tespit etme karmaşık görevini yerine getiren işlev

Kavşak yoksa işlev sıfır, varsa sıfır olmayan kayan nokta sayısı döndürür. Ayrıca bir yan etkisi vardır: kesişimin koordinatları z $ dizesine eklenir. Ek olarak, BBC basic'de, ana programın aynı isimde bir değişken olmaması koşuluyla bir fonksiyonun değişkenleri ana program tarafından görülebilir (fonksiyon bittikten sonra bile).

Bu nedenle, ana program değişken erişimi olan xve yve mve nşimdiki ve önceki kesişme koordinatlarını depolar. Bu, bir noktada kesişen üç çizgiyi değil, gerçekten bir üçgen bulup bulmadığımızı tespit etmek için kullanılır.

  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.
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.