Площадь поверхности тетраэдра


16

Соревнование

Эта задача очень проста. По четырем трехмерным точкам вычислите площадь поверхности тетраэдра, который они образуют. Это , поэтому выигрывает самый короткий код. Применяются стандартные лазейки с дополнительным условием, что любая встроенная функция для выполнения этой задачи с учетом четырех пунктов запрещена.

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

Для тех из вас, кто не знает, тетраэдр - это трехмерное тело, образованное четырьмя треугольными гранями.

пример

# 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 на четырех отдельных строках. Я отредактирую вопрос, чтобы уточнить это.
Stokastic

Может ли вход быть [[list],[of],[lists]]?
Фосген

@phosgene Мне нравится думать, что чтение входных данных является частью проблемы, поэтому я собираюсь сказать нет. Я постараюсь быть более снисходительным со спецификациями ввода в будущих задачах.
Stokastic

Это правильный или неправильный тетраэдр?
Джеймс Уильямс

@JamesWilliams приведенный пример нерегулярен. Ваша программа должна обрабатывать любые входные данные, включая обычные тетраэдры.
Stokastic

Ответы:


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

Matlab / Octave 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, обрабатывает их как трехмерные векторы и вычисляет квадратичную величину их перекрестного произведения.

                        ⊂⍺   # 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

@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
Я использовал тот же метод для тестирования моего решения. Я должен попробовать гольф и опубликовать его позже.
Stokastic

1
Ваш for i in">"*4умный
Stokastic

Вы можете жестко закодировать длину 3 вместо использования len (i) в вашей функции диапазона.
Stokastic

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]


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

Он использует ту же процедуру, что и laurencevs.


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

С, 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.