Obszar wypukłego kadłuba 2D

11

Otrzymujesz tablicę / listę / wektor par liczb całkowitych reprezentujących współrzędne kartezjańskie (x,y) punktów na płaszczyźnie euklidesowej 2D; wszystkie współrzędne mają wartości od 104 do 104 , dozwolone są duplikaty. Znajdź obszar wypukłego kadłuba tych punktów, zaokrąglony do najbliższej liczby całkowitej; dokładny punkt środkowy powinien być zaokrąglony do najbliższej liczby całkowitej. Liczb zmiennoprzecinkowych można używać w obliczeniach pośrednich, ale tylko wtedy, gdy można zagwarantować, że końcowy wynik będzie zawsze poprawny. To jest , więc wygrywa najkrótszy prawidłowy program.

Wypukłe kadłuba z zestawu punktów P jest najmniejszy zbiór wypukły zawierający P . Na płaszczyźnie euklidesowej dla każdego pojedynczego punktu (x,y) jest to sam punkt; dla dwóch odrębnych punktów jest to linia je zawierająca, dla trzech niekolinearnych punktów jest to trójkąt, który tworzą i tak dalej.

Dobre wizualne wyjaśnienie, czym są wypukłe kadłuby, najlepiej opisać jako wyobrażenie sobie wszystkich punktów jako gwoździ w drewnianej desce, a następnie rozciągnięcie gumowej opaski wokół nich, aby zamknąć wszystkie punkty:
wprowadź opis zdjęcia tutaj

Niektóre przypadki testowe:

Input: [[50, -13]]
Result: 0

Input: [[-25, -26], [34, -27]]
Result: 0

Input: [[-6, -14], [-48, -45], [21, 25]]
Result: 400

Input: [[4, 30], [5, 37], [-18, 49], [-9, -2]]
Result: 562

Input: [[0, 16], [24, 18], [-43, 36], [39, -29], [3, -38]]
Result: 2978

Input: [[19, -19], [15, 5], [-16, -41], [6, -25], [-42, 1], [12, 19]]
Result: 2118

Input: [[-23, 13], [-13, 13], [-6, -7], [22, 41], [-26, 50], [12, -12], [-23, -7]]
Result: 2307

Input: [[31, -19], [-41, -41], [25, 34], [29, -1], [42, -42], [-34, 32], [19, 33], [40, 39]]
Result: 6037

Input: [[47, 1], [-22, 24], [36, 38], [-17, 4], [41, -3], [-13, 15], [-36, -40], [-13, 35], [-25, 22]]
Result: 3908

Input: [[29, -19], [18, 9], [30, -46], [15, 20], [24, -4], [5, 19], [-44, 4], [-20, -8], [-16, 34], [17, -36]]
Result: 2905
Vladimir Reshetnikov
źródło
2
Czy masz jakieś przypadki testowe?
Maltysen
17
Nie liczenie białych znaków w kodzie golfowym jest złym pomysłem, prowadzi do przesyłania z dużymi ciągami białych znaków i ogólnym kodem do konwersji łańcucha na kod i wykonania go.
xnor
4
dokładny punkt środkowy należy zaokrąglić do najbliższej liczby całkowitej : zastanawiasz się, jakie jest tego uzasadnienie?
Arnauld,
4
[[0, 0], [1, 1], [0, 1]]1/20
6
Zazwyczaj wyzwania są samodzielne, ale to nie jest. Czy możesz wyjaśnić, czym jest wypukły kadłub i jak go obliczyć? Lub wskaż jakieś referencyjne źródło online?
Olivier Grégoire,

Odpowiedzi:

9

SQL Server 2012+, 84 bajty

SELECT Round(Geometry::ConvexHullAggregate(Geometry::Point(x,y,0)).STArea(),0)FROM A

Wykorzystuje funkcje geometryczne i agregacje w SQL Server. Współrzędne są z tabeli Az kolumnami xi y.

MickyT
źródło
9

Java 10, 405 ... już nie pasowało; zobacz historię edycji. 317 316 bajtów

P->{int n=P.length,l=0,i=0,p,q,t[],h[][]=P.clone(),s=0;for(;++i<n;)l=P[i][0]<P[l][0]?i:l;p=l;do for(h[s++]=P[p],q=-~p%n,i=-1;++i<n;q=(t[1]-P[p][1])*(P[q][0]-t[0])<(t[0]-P[p][0])*(P[q][1]-t[1])?i:q)t=P[i];while((p=q)!=l);for(p=i=0;i<s;p-=(t[0]+h[++i%s][0])*(t[1]-h[i%s][1]))t=h[i];return Math.round(.5*p/~(p%=2))*~p;}

-52 bajtów dzięki @ OlivierGrégoire
-3 bajtów dzięki @PeterTaylor
-7 bajtów dzięki @ceilingcat

Wypróbuj online.

Lub 299 bajtów bez zaokrąglenia .. .

Wyjaśnienie:

Są trzy kroki do zrobienia:

  1. Oblicz punkty dla wypukłego kadłuba na podstawie współrzędnych wejściowych (używając algorytmu / zawijania Jarvisa )
  2. Oblicz powierzchnię tego wypukłego kadłuba
  3. Zaokrąglenie bankiera ..

Aby obliczyć współrzędne wchodzące w skład wypukłego kadłuba, stosujemy następujące podejście:

lppl

wprowadź opis zdjęcia tutaj

Co do kodu:

P->{                      // Method with 2D integer array as parameter & long return-type
  int n=P.length,         //  Integer `n`, the amount of points in the input
      l=0,                //  Integer `l`, to calculate the left-most point
      i=0,                //  Index-integer `i`
      p,                  //  Integer `p`, which will be every next counterclockwise point
      q,                  //  Temp integer `q`
      t[],                //  Temp integer-array/point
      h[][]=P.clone(),    //  Initialize an array of points `h` for the Convex Hull
      s=0;                //  And a size-integer for this Convex Hull array, starting at 0
  for(;++i<n;)            //  Loop `i` in the range [1, `n`):
    l=                    //   Change `l` to:
      P[i][0]<P[l][0]?    //   If i.x is smaller than l.x:
       i                  //    Replace `l` with the current `i`
      :l;                 //   Else: leave `l` unchanged
  p=l;                    //  Now set `p` to this left-most coordinate `l`
  do                      //  Do:
    for(h[s++]=P[p],      //   Add the `p`'th point to the 2D-array `h`
        q=-~p%n,          //   Set `q` to `(p+1)` modulo-`n`
        i=-1;++i<n;       //    Loop `i` in the range [0, `n`):
        ;q=               //      After every iteration: change `q` to:
                          //       We calculate: (i.y-p.y)*(q.x-i.x)-(i.x-p.x)*(q.y-i.y), 
                          //       which results in 0 if the three points are collinear;
                          //       a positive value if they are clockwise;
                          //       or a negative value if they are counterclockwise
           (t[1]-P[p][1])*(P[q][0]-t[0])<(t[0]-P[p][0])*(P[q][1]-t[1])?
                          //       So if the three points are counterclockwise:
            i             //        Replace `q` with `i`
           :q)            //       Else: leave `q` unchanged
      t=P[i];             //     Set `t` to the `i`'th Point (to save bytes)
  while((p=q)             //  And after every while-iteration: replace `p` with `q`
             !=l);        //  Continue the do-while as long as `p` is not back at the
                          //  left-most point `l` yet
  // Now step 1 is complete, and we have our Convex Hull points in the List `h`

  for(p=i=0;              //  Set `p` (the area) to 0
      i<s                 //  Loop `i` in the range [0, `s`):
      ;p-=                //    After every iteration: Decrease the area `p` by:
        (t[0]+h[++i%s][0])//     i.x+(i+1).x
        *(t[1]-h[i%s][1]))//     Multiplied by i.y-(i+1).y
    t=h[i];               //   Set `t` to the `i`'th point (to save bytes)
 return Math.round(.5*p/~(p%=2))*~p;}
                          //  And return `p/2` rounded to integer with half-even
Kevin Cruijssen
źródło
1
Daj nam kontynuować tę dyskusję w czacie .
Kevin Cruijssen
6

JavaScript (ES6),  191  189 bajtów

Implementuje marsz Jarvisa (inaczej algorytm pakowania prezentów).

P=>(r=(g=p=>([X,Y]=P[p],Y*h-X*v)+(P.map(([x,y],i)=>q=(y-Y)*(P[q][0]-x)<(x-X)*(P[q][1]-y)?i:q,q=P[++p]?p:0,h=X,v=Y)|q?g(q):V*h-H*v))(v=h=0,([[H,V]]=P.sort(([x],[X])=>x-X)))/2)+(r%1&&r&1)/2|0

Wypróbuj online!

Lub 170 bajtów bez uciążliwego schematu zaokrąglania.

Arnauld
źródło
Zaokrąglenie było tylko czerwonym śledziem, ponieważ podwójna powierzchnia jest zawsze dokładnie całkowita.
Vladimir Reshetnikov
4
@VladimirReshetnikov Z ciekawości: jeśli wiedziałeś, że zaokrąglanie to czerwony śledź, to po co dodawać go, aby odwrócić uwagę od skądinąd dobrego wyzwania? Nie wszystkie języki mają wbudowane zaokrąglanie Bankera, nawet najwyraźniej takie języki, jak JS i Java. Ogólnie podoba mi się to wyzwanie i podobało mi się pisanie odpowiedzi w Javie, ale zaokrąglenie i brak wyjaśnienia, czym jest Convex Hull, aby uczynić wyzwanie samodzielnym, powstrzymało mnie od poparcia go, tbh .. PS: Przepraszam @Arnauld, aby zrobić to jako skomentuj swoją odpowiedź ..
Kevin Cruijssen
4

R , 85 81 78 bajtów

function(i,h=chull(i),j=c(h,h[1]))round((i[h,1]+i[j[-1],1])%*%diff(-i[j,2])/2)

Wypróbuj online!

Pobiera dane wejściowe jako macierz 2-kolumnową - pierwsza dla x, druga dla y. R roundfaktycznie używa metody zaokrąglania przez bankiera, więc mamy tu szczęście.

i(xi1+x)(yi1yi)/2

Dzięki Giuseppe za -3 bajty.

Kirill L.
źródło
3

[Pakiet R + sp], 55 bajtów

function(x)round(sp::Polygon(x[chull(x),,drop=F])@area)

Wypróbuj w RDRR

Funkcja, która pobiera macierz anx 2 i zwraca zaokrąglony obszar. To używa sppakietu. drop=FJest potrzebne do obsługi sprawy jeden współrzędnych. RDRR używany do demonstracji, ponieważ TIO nie ma sppakietu.

Nick Kennedy
źródło