Área de superfície do tetraedro

16

O desafio

Esse desafio é muito direto. Dados quatro pontos tridimensionais, calcule a área da superfície do tetraedro que eles formam. Isso é , então o código mais curto vence. Aplicam-se brechas padrão, com a estipulação adicional de que é proibida qualquer função interna para executar esta tarefa, com quatro pontos.

Você pode assumir que todos os quatro pontos serão distintos e serão dados via STDIN, 1 ponto por linha. Cada ponto consistirá em três números inteiros não assinados de 16 bits. O formato exato de cada ponto pode ser modificado se facilitar as coisas, como três números inteiros separados por espaço. Porém, ter cada ponto em uma linha separada é obrigatório. A saída deve ser feita por STDOUT, com pelo menos 2 casas decimais.

Para aqueles que não sabem, um tetraedro é um sólido 3-d, formado por 4 faces triangulares.

Exemplo

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

# output
2932496435.95

Deixe uma nota se notar que minha matemática está errada.

stokastic
fonte
@BetaDecay Não, a ideia é que eles sejam inseridos via STDIN em quatro linhas separadas. Vou editar a pergunta para esclarecer isso.
stokastic
A entrada pode ser a [[list],[of],[lists]]?
fosgênio
@phosgene Eu gosto de pensar que ler a entrada faz parte do desafio, então vou dizer não. Vou tentar ser mais branda com as especificações de entrada em desafios futuros.
stokastic
Este é um tetraedro regular ou irregular?
James Williams
@JamesWilliams o exemplo postado é irregular. Porém, seu programa deve lidar com qualquer entrada, incluindo tetraedros regulares.
stokastic

Respostas:

5

Python, 198 178 161 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

O formato de entrada é o indicado na pergunta.

Ele calcula o comprimento das arestas adjacentes a cada uma das faces e depois usa a fórmula de Heron .

Keith Randall
fonte
4

Matlab / Octave 103

Eu assumo os valores a serem armazenados na variável c. Isso usa o fato de que a área de um triângulo é a metade do comprimento do produto cruzado de dois de seus vetores laterais.

%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
flawr
fonte
Cada ponto deve ser inserido em uma linha separada como entrada padrão.
DavidC
Inicialmente, pensei que não houvesse entrada padrão no Matlab, mas descobri uma função que pode ser usada para simular isso na janela de comando; portanto, agora você pode passar a entrada como em outros idiomas.
flawr
Interessante. Esse é o mesmo comando que o Mathematica usa,Input[]
DavidC 4/04
Por que você acha isso interessante? 'input' me parece um nome bastante genérico para uma função que faz isso.
flawr
Até ontem, eu realmente não sei o que "a entrada padrão" significava, e eu pensei que Mathematica não tinha entrada "standard", mesmo que eu tinha usado regularmente Input[], InputString[], Import[], e ImportString[].
DavidC
4

APL, 59

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

Funciona calculando produtos cruzados

Explicação
A primeira linha define uma função que recebe dois argumentos (implicitamente nomeados e ), espera implicitamente que sejam matrizes numéricas de comprimento 3, as trata como vetores 3D e calcula a magnitude quadrada de seu produto 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`

A segunda linha faz o 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
fonte
Se você não tem certeza se são hieróglifos ou um arquivo DLL corrompido, provavelmente será APL. Você poderia explicar um pouco mais o que alguns desses símbolos fazem? Não é que eu quero aprender isso, mas eu ainda estou bastante intrigado pela forma como você pode programar com esses símbolos aparentemente obscuros = P
flawr
@ flawr Eu normalmente faço isso porque o golfe no APL se resume principalmente ao design de algoritmos e provavelmente resultaria em uma abordagem incomum para o problema. Mas eu senti que "calcular produto cruzado" transmite o suficiente sobre o algoritmo aqui. Se você quiser uma explicação completa, farei isso ainda hoje.
TwiNight
A ideia de calcular o produto cruzado era clara, mas o código em si me deixa sem nenhuma pista, então pensei em algumas palavras sobre quais partes do código fazem o que seria ótimo, mas é claro que não quero insistir para que você escreva uma explicação detalhada!
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))

Isso usa:

  • O Teorema de Pitágoras (em 3D) para calcular o comprimento de cada linha
  • Fórmula de Heron para calcular a área de cada triângulo
monopolo
fonte
11
Eu usei o mesmo método para testar minha solução. Vou ter que tentar jogar o meu e publicá-lo mais tarde.
stokastic
11
Você for i in">"*4é inteligente
stokastic
Você pode codificar um comprimento de 3, em vez de usar len (i) na sua função de intervalo.
stokastic
11
Você pode salvar mais alguns caracteres usando a raiz quadrada como x**0.5, em vez de math.sqrt(x).
Snorfalorpagus
11
Você pode salvar dois bytes, colocando def a(t,u,v)em uma linha assim: 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

Ele encontra os comprimentos das bordas do tetraedro e usa a fórmula de Heron para determinar as áreas das faces.

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

Existe uma rota mais direta que requer apenas 60 caracteres , mas viola as regras na medida em que calcula a área de cada face com uma função integrada Area:

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

Sábio - 103

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

A parte de leitura de entrada é adaptada da resposta de Keith Randall .

Wrzlprmft
fonte
0

Python - 260

Não sei ao certo qual é a etiqueta ao postar respostas para suas próprias perguntas, mas ela é a minha solução, que usei para verificar meu exemplo:

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

Ele usa o mesmo procedimento que os laurencevs.

stokastic
fonte
4
Como regra geral, é uma boa idéia aguardar alguns dias antes de responder sua própria pergunta, especialmente se sua pontuação for baixa, para não diminuir a motivação dos espectadores.
Blackhole
Algumas dicas: Você pode salvar alguns caracteres por r=range. lambdaé mais curto que def. math.sqrtpode ser substituído por (…)**.5. p=copy.copy(P);p.pop(j);pode ser reduzido para p=P[:j-1]+P[j:]. Aé usado apenas uma vez.
Wrzlprmft
0

C, 303

Excluindo espaços em branco desnecessários. No entanto, ainda há muito golfe a ser feito aqui (tentarei voltar e fazer isso mais tarde). É a primeira vez que declaro um forloop em um#define . Eu sempre achei maneiras de minimizar o número de loops antes.

Eu tive que mudar de floatpara doubleobter a mesma resposta que o OP para o caso de teste. Antes disso, eram 300 rodadas.

scanf funciona da mesma forma, se você separa sua entrada com espaços ou novas linhas, para que você possa formatá-la em quantas ou quantas linhas desejar.

#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
fonte