Á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.


@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 .


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

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

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

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]

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 .


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.


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);       
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.