Площа 2D опуклого корпусу


11

Вам надається масив / список / вектор пар цілих чисел, що представляють декартові координати (x,y) точок на 2D евклідовій площині; всі координати між 104 та 104 , копії дозволені. Знайдіть площу опуклого корпусу цих точок, закруглену до найближчого цілого числа; точну середину слід округлювати до найближчого парного числа. Ви можете використовувати номери з плаваючою комою в проміжних обчисленнях, але тільки якщо ви можете гарантувати, що кінцевий результат буде завжди правильним. Це , тому виграє найкоротша правильна програма.

Опукла оболонка безлічі точок P є найменше опукле безліч, що містить P . На площині Евкліда для будь-якої окремої точки (x,y) - сама точка; для двох чітких точок - це пряма, що їх містить, для трьох неколінеарних точок - це трикутник, який вони утворюють тощо.

Хороше візуальне пояснення того, що опуклий корпус, найкраще описати як уявлення всіх точок як цвяхів на дерев'яній дошці, а потім натягування гумки навколо них, щоб укласти всі точки:
введіть тут опис зображення

Деякі тестові випадки:

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

2
Чи є у вас тестові випадки?
Мальтісен

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

4
точну середину слід округлити до найближчого навіть цілого числа : просто цікаво, що мотивує це?
Арнольд

4
[[0, 0], [1, 1], [0, 1]]1/20

6
Зазвичай виклики є самостійними, але це не так. Чи можете ви пояснити, що таке опуклий корпус, і як його обчислити? Або вказати на якийсь довідковий інтернет-ресурс?
Олів'є

Відповіді:


9

SQL Server 2012+, 84 байти

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

Використовує функції геометрії та агрегати в SQL Server. Координати - з таблиці Aзі стовпцями xта y.


9

Java 10, 405 ... більше не підходили; див. історію редагування .. 317 316 байт

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 байт завдяки @ OlivierGrégoire
-3 байти завдяки @PeterTaylor
-7 байт завдяки @ceilingcat

Спробуйте в Інтернеті.

Або 299 байт без округлення .. .

Пояснення:

Виконайте три кроки:

  1. Обчисліть точки для опуклого корпусу на основі вхідних координат (використовуючи алгоритм / загортання Джарвіса )
  2. Обчисліть площу цього опуклого корпусу
  3. Заокруглення банкіра ..

Для обчислення координат, що входять до складу опуклого корпусу, ми використовуємо такий підхід:

lppl

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

Щодо коду:

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



6

JavaScript (ES6),  191  189 байт

Реалізує марш Jarvis (також алгоритм упаковки подарунків).

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

Спробуйте в Інтернеті!

Або 170 байт без громіздкої схеми округлення.


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

4
@VladimirReshetnikov З цікавості: якщо ви знали, що округлення - це червона оселедець, то навіщо додати його, щоб відволіктись від інакшого доброго виклику? Мені подобається виклик в цілому і мені подобається писати свою відповідь на Java, але округлення та відсутність пояснень, що таке Convex Hull, щоб зробити виклик самодостатньою, утримали мене від того, щоб подати цю заяву, tbh .. PS: Вибачте @Arnauld, щоб зробити це як прокоментуйте свою відповідь ..
Кевін Кройсейсен

4

R , 85 81 78 байт

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

Спробуйте в Інтернеті!

Приймає дані як матрицю з двома стовпцями - перший для x, другий для y. R roundфактично використовує метод округлення банкіра, тому нам тут пощастило.

i(xi1+x)(yi1yi)/2

Завдяки Джузеппе за -3 байти.


3

[Пакет R + sp], 55 байт

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

Спробуйте це в RDRR

Функція, яка приймає матрицю anx 2 і повертає округлу область. Для цього використовується spпакет. drop=FПотрібно обробляти випадок один координатного. RDRR використовується для демонстрації, оскільки TIO не вистачає spпакета.

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