Área de superficie del tetraedro

16

El reto

Este desafío es muy sencillo. Dados cuatro puntos tridimensionales, calcule el área de superficie del tetraedro que forman. Este es el , por lo que gana el código más corto. Se aplican las lagunas estándar, con la estipulación adicional de que cualquier función incorporada para realizar esta tarea tiene cuatro puntos prohibidos.

Puede suponer que los cuatro puntos serán distintos y se otorgarán a través de STDIN, 1 punto por línea. Cada punto constará de tres enteros sin signo de 16 bits. El formato exacto de cada punto se puede modificar si facilita las cosas, como tres enteros separados por espacios. Sin embargo, es obligatorio tener cada punto en una línea separada. La salida debe ser a través de STDOUT, con al menos 2 decimales.

Para aquellos de ustedes que no saben, un tetraedro es un sólido tridimensional, formado por 4 caras triangulares.

Ejemplo

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

# output
2932496435.95

Por favor, deje una nota si nota que mis matemáticas están mal.

estocástico
fuente
@BetaDecay No, la idea es que se ingresarán a través de STDIN en cuatro líneas separadas. Editaré la pregunta para aclarar esto.
Stokastic
¿La entrada puede ser a [[list],[of],[lists]]?
fosgeno el
@phosgene Me gusta pensar que leer la entrada es parte del desafío, así que voy a decir que no. Intentaré ser más indulgente con las especificaciones de entrada en futuros desafíos.
Stokastic
¿Es este un tetraedro regular o irregular?
James Williams el
@JamesWilliams el ejemplo publicado es irregular. Sin embargo, su programa debe manejar cualquier entrada, incluidos los tetraedros regulares.
Stokastic

Respuestas:

5

Python, 198178161 caracteres

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

El formato de entrada es el que figura en la pregunta.

Calcula la longitud de los bordes adyacentes a cada una de las caras y luego usa la fórmula de Heron .

Keith Randall
fuente
4

Matlab / Octave 103

Supongo que los valores se almacenarán en la variable c. Esto utiliza el hecho de que el área de un triángulo es la mitad de la longitud del producto transversal de dos de sus vectores laterales.

%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
falla
fuente
Cada punto debe ingresarse en una línea separada como entrada estándar.
DavidC
Primero pensé que no existe una entrada estándar en Matlab, pero descubrí una función que se puede usar para simular esto a través de la ventana de comandos, por lo que ahora puede pasar la entrada como podría en otros idiomas.
flawr
Interesante. Ese es el mismo comando que usa Mathematica,Input[]
DavidC
¿Por qué crees que esto es interesante? 'input' me parece un nombre bastante genérico para una función que hace esto.
flawr
Hasta ayer, no sabía qué "entrada estándar" significaba, y pensé que Mathematica no tenía entrada "estándar", a pesar de que había utilizado con regularidad Input[], InputString[], Import[], y ImportString[].
DavidC
4

APL, 59

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

Funciona calculando productos cruzados

Explicación
La primera línea define una función que toma dos argumentos (implícitamente llamado y ), implícitamente espera que sean matrices numéricas de longitud 3, los trata como vectores 3d y calcula la magnitud al cuadrado de su producto cruzado.

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

La segunda línea hace el resto.

                         ⎕⎕⎕-⊂⎕ # 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
TwiNight
fuente
Si no está seguro de si se trata de jeroglíficos o un archivo dll dañado, probablemente será APL. ¿Podría explicar un poco más qué hacen algunos de esos símbolos? No es que quiera aprenderlo, pero todavía estoy bastante intrigado por cómo puedes programar con esos símbolos aparentemente oscuros = P
flawr
@flawr Normalmente lo hago porque el golf en APL se reduce principalmente al diseño de algoritmos y probablemente resultaría en un enfoque poco común del problema. Pero sentí que "calcular el producto cruzado" transmite bastante sobre el algoritmo aquí. Si quieres una explicación completa, lo haré más tarde hoy.
TwiNight
La idea de calcular el producto cruzado era clara, pero el código en sí mismo me deja sin ninguna pista, así que solo pensé algunas palabras sobre qué partes del código hacen lo que sería genial, pero, por supuesto, no quiero instarlo a que lo haga. escribe una explicación detallada!
flawr
3

Python 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))

Esto usa:

  • El teorema de Pitágoras (en 3D) para calcular la longitud de cada línea
  • Fórmula de Heron para calcular el área de cada triángulo
monopolo
fuente
1
Usé el mismo método para probar mi solución. Tendré que intentar jugar al golf y publicarlo más tarde.
stokastic
1
Tu for i in">"*4es inteligente
stokastic
Puede codificar una longitud de 3, en lugar de usar len (i) en su función de rango.
Stokastic
1
Podría guardar algunos caracteres más haciendo la raíz cuadrada como x**0.5, en lugar de math.sqrt(x).
Snorfalorpagus
1
Puede guardar dos bytes poniendo def a(t,u,v)en una sola línea, así: def a(t,u,v):w=(t+u+v)/2;return(w*(w-t)*(w-u)*(w-v))**0.5.
Beta Decay
2

Mathematica 168 154

Esto encuentra las longitudes de los bordes del tetraedro y usa la fórmula de Heron para determinar las áreas de las caras.

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

Hay una ruta más directa que requiere solo 60 caracteres , pero viola las reglas en la medida en que calcula el área de cada cara con una función incorporada Area:

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

Sabio - 103

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

La parte de lectura de entrada está adaptada de la respuesta de Keith Randall .

Wrzlprmft
fuente
0

Python - 260

No estoy seguro de cuál es la etiqueta al publicar respuestas a sus propias preguntas, pero ella es mi solución, que utilicé para verificar mi ejemplo: golf:

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

Utiliza el mismo procedimiento que laurencevs.

estocástico
fuente
44
Como regla general, es una buena idea esperar unos días antes de responder a su propia pregunta, especialmente si su puntaje es bajo, para no enfriar la motivación de los espectadores.
Blackhole
Algunos consejos: puede guardar algunos caracteres r=range. lambdaes más corto que def. math.sqrtpuede ser sustituido por (…)**.5. p=copy.copy(P);p.pop(j);se puede acortar a p=P[:j-1]+P[j:]. Asolo se usa una vez.
Wrzlprmft
0

C, 303

Excluyendo espacios en blanco innecesarios. Sin embargo, todavía hay mucho golf por hacer aquí (intentaré volver y hacerlo más tarde). Es la primera vez que declaro un forbucle en un #define. Siempre he encontrado formas de minimizar el número de bucles antes.

Tuve que cambiar de floata doublepara obtener la misma respuesta que el OP para el caso de prueba. Antes de eso, era una ronda 300.

scanf funciona igual si separa su entrada con espacios o líneas nuevas, por lo que puede formatearla en tantas o tan pocas líneas como desee.

#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);       
}
Level River St
fuente