Площа поверхні тетраедра


16

Змагання

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

Ви можете припустити, що всі чотири бали будуть виразними та будуть надані через STDIN, 1 бал на рядок. Кожна точка буде складатися з трьох 16-бітних непідписаних цілих чисел. Точний формат кожної точки може бути змінений, якщо це полегшує речі, наприклад, три цілих цілих числа. Однак наявність кожної точки на окремому рядку є обов'язковою. Вихід повинен бути через STDOUT, щонайменше, до 2 знаків після коми.

Для тих із вас, хто не знає, тетраедр - це 3-денне тверде тіло, утворене 4 трикутними гранями.

Приклад

# input (format is up to you, see clarification above)
[23822, 47484, 57901]
[3305, 23847, 42159]
[19804, 11366, 14013]
[52278, 28626, 52757]

# output
2932496435.95

Будь ласка, залиште записку, якщо ви помітили, що моя математика неправильна.


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

Чи може вхід бути a [[list],[of],[lists]]?
фосген

@phosgene Мені подобається, що читання матеріалів є частиною завдання, тому я хочу сказати "ні". Я постараюся бути більш поблажливим до вхідних специфікацій у майбутніх викликах.
стокастик

Це регулярний чи неправильний тетраедр?
Джеймс Вільямс

@JamesWilliams наведений приклад нерегулярний. Програма повинна обробляти будь-які дані, включаючи звичайні тетраедри.
стокастик

Відповіді:


5

Пітон, 198 178 161 символів

V=eval('input(),'*4)
A=0
for i in range(4):F=V[:i]+V[i+1:];a,b,c=map(lambda e:sum((a-b)**2for a,b in zip(*e)),zip(F,F[1:]+F));A+=(4*a*b-(a+b-c)**2)**.5
print A/4

Формат введення вказаний у запитанні.

Він обчислює довжину ребер, прилеглих до кожного з граней, а потім використовує формулу Герона .


4

Матлаб / Октав 103

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

%input
[23822, 47484, 57901;
3305, 23847, 42159;
19804, 11366, 14013;
52278, 28626, 52757]



%actual code
c=input('');
a=0;
for i=1:4;
    d=c;d(i,:)=[];
    d=d(1:2,:)-[1 1]'*d(3,:);
    a=a+norm(cross(d(1,:),d(2,:)))/2;
end
a

Кожна точка повинна бути введена в окремий рядок як стандартне введення.
DavidC

Я спершу подумав, що в Matlab немає такого поняття, як стандартний ввід, але я виявив функцію, яку можна використати для імітації цього за допомогою вікна команд, тож тепер ви можете передати введення так, як могли б іншими мовами.
flawr

Цікаво. Це та сама команда, яку використовує Mathematica,Input[]
DavidC

Чому ви вважаєте, що це цікаво? 'input' мені здається досить загальною назвою функції, яка робить це.
flawr

До вчорашнього дня, я дійсно не знаю , що «стандартний ввід» мав в виду, і я подумав , що Mathematica не мають «стандартний» вхід, хоча я регулярно використовував Input[], InputString[], Import[]і ImportString[].
DavidC

4

APL, 59

f←{+.×⍨⊃1 2-.⌽(⊂⍵)×1 2⌽¨⊂⍺}
.5×.5+.*⍨(f/2-/x),2f/4⍴x←⎕⎕⎕-⊂⎕

Працює шляхом обчислення крос-продуктів

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

                        ⊂⍺   # Wrap the argument in a scalar
                   1 2⌽¨     # Create an array of 2 arrays, by rotating `⊂⍺` by 1 and 2 places
             (⊂⍵)×           # Coordinate-wise multiply each of them with the other argument
        1 2-.⌽               # This is a shorthand for:
        1 2  ⌽               #   Rotate the first array item by 1 and the second by 2
           -.                #   Then subtract the second from the first, coordinate-wise
       ⊃                     # Unwrap the resulting scalar to get the (sorta) cross product
   +.×                       # Calculate the dot product of that...
      ⍨                      # ...with itself
f←{+.×⍨⊃1 2-.⌽(⊂⍵)×1 2⌽¨⊂⍺} # Assign function to `f`

Другий рядок робить все інше.

                         ⎕⎕⎕-⊂⎕ # Take 4 array inputs, create an array of arrays by subtracting one of them from the other 3
                       x←        # Assign that to x
                     4⍴          # Duplicate the first item and append to the end
                  2f/            # Apply f to each consecutive pair
            2-/x                 # Apply subtraction to consecutive pairs in x
          f/                     # Apply f to the 2 resulting arrays
         (f/2-/x),2f/4⍴x←⎕⎕⎕-⊂⎕ # Concatenate to an array of 4 squared cross products
   .5+.*⍨                        # Again a shorthand for:
   .5  *⍨                        #   Take square root of each element (by raising to 0.5)
     +.                          #   And sum the results
.5×                              # Finally, divide by 2 to get the answer

Якщо ви не впевнені, це ієрогліфи чи пошкоджений файл DLL, ймовірно, це буде APL. Не могли б ви пояснити дещо детальніше, що роблять деякі з цих символів? Це не те, що я хочу це навчитися, але мене все ще дуже заінтригує те, як можна програмувати ті, здавалося б, незрозумілі символи = P
недолік

@flawr Я зазвичай це роблю, тому що гольф в APL в основному зводиться до розробки алгоритмів і, швидше за все, це призведе до нечастого підходу до проблеми. Але я відчував, що «обчислення крос-продукту» передає тут досить про алгоритм. Якщо ви хочете отримати повне пояснення, я зроблю це пізніше сьогодні.
TwiNight

Ідея обчислення крос-продукту була зрозумілою, але сам код залишає мене без жодної підказки, тому я просто подумав кілька слів про те, які частини коду роблять, що було б чудово, але, звичайно, я не хочу закликати вас написати детальне пояснення!
flawr

3

Пітон 3, 308 298 292 279 258 254

from itertools import*
def a(t,u,v):w=(t+u+v)/2;return(w*(w-t)*(w-u)*(w-v))**.5
z,x,c,v,b,n=((lambda i,j:(sum((i[x]-j[x])**2for x in[0,1,2]))**.5)(x[0],x[1])for*x,in combinations([eval(input())for i in">"*4],2))
print(a(z,x,v)+a(z,c,b)+a(b,v,n)+a(x,c,n))

Для цього використовується:

  • Теорема Піфагора (у 3D) для визначення довжини кожного рядка
  • Формула чаплі для опрацювання площі кожного трикутника

1
Я використовував той самий метод для тестування свого рішення. Мені доведеться спробувати шахту для гольфу і опублікувати її пізніше.
стокастик

1
Ваш for i in">"*4розумний
стокастик

Ви можете жорстко кодувати довжину 3, замість того, щоб використовувати len (i) у функції діапазону.
стокастик

1
Ви можете зберегти ще кілька символів, роблячи квадратний корінь як x**0.5, а не math.sqrt(x).
Snorfalorpagus

1
Ви можете зберегти два байта, поставивши def a(t,u,v)на один рядок наступним чином: def a(t,u,v):w=(t+u+v)/2;return(w*(w-t)*(w-u)*(w-v))**0.5.
Бета-розпад

2

Mathematica 168 154

Це знаходить довжини ребер тетраедра та використовує формулу Герона для визначення площ граней.

t = Subsets; p = Table[Input[], {4}];
f@{a_, b_, c_} := Module[{s = (a + b + c)/2}, N[Sqrt[s (s - #) (s - #2) (s -#3)] &[a, b, c], 25]]
  Tr[f /@ (EuclideanDistance @@@ t[#, {2}] & /@ t[p, {3}])]

Існує більш прямий маршрут, який вимагає лише 60 символів , але він порушує правила, якщо він обчислює область кожного обличчя за допомогою вбудованої функції Area:

p = Table[Input[], {4}];
N[Tr[Area /@ Polygon /@ Subsets[p, {3}]], 25]

1

Шавлія - ​​103

print sum((x*x*y*y-x*y*x*y)^.5for x,y in map(differences,Combinations(eval('vector(input()),'*4),3)))/2

Частина введення-читання адаптована з відповіді Кіта Рендалла .


0

Пітон - 260

Я не впевнений, що таке етикет про розміщення відповідей на ваші власні запитання, але вона - це моє рішення, яке я використовував для перевірки свого прикладу, гольфу:

import copy,math
P=[input()for i in"1234"]
def e(a, b):return math.sqrt(sum([(b[i]-a[i])**2 for i in range(3)]))
o=0
for j in range(4):p=copy.copy(P);p.pop(j);a,b,c=[e(p[i],p[(i+1)%3])for i in range(3)];s=(a+b+c)/2;A=math.sqrt(s*(s-a)*(s-b)*(s-c));o+=A
print o

Він використовує ту саму процедуру, що і лауренцев.


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

Кілька порад: деякі символи можна зберегти за допомогою r=range. lambdaкоротше, ніж def. math.sqrtможна замінити на (…)**.5. p=copy.copy(P);p.pop(j);можна скоротити до p=P[:j-1]+P[j:]. Aвикористовується лише один раз.
Wrzlprmft

0

C, 303

Виключаючи зайвий пробіл. Тим не менш, тут ще дуже багато гольфу потрібно зробити (я спробую повернутися і зробити це пізніше.) Це перший раз, коли я оголосив forцикл в #define. Я завжди знаходив способи мінімізувати кількість петель раніше.

Мені довелося перейти з, floatщоб doubleотримати ту саму відповідь, що і ОП для тестового випадку. До цього це було 300 круглих.

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

#define F ;for(i=0;i<12;i++)
#define D(k) (q[i]-q[(i+k)%12])
double q[12],r[12],s[4],p,n;

main(i){
  F scanf("%lf",&q[i])
  F r[i/3*3]+=D(3)*D(3),r[i/3*3+1]+=D(6)*D(6)
  F r[i]=sqrt(r[i])
  F i%3||(s[i/3]=r[(i+3)%12]/2),s[i/3]+=r[i]/2
  F i%3||(p=s[i/3]-r[(i+3)%12]),p*=s[i/3]-r[i],n+=(i%3>1)*sqrt(p)   
  ;printf("%lf",n);       
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.