Решение треугольников с помощью тригонометрии


13

Время выкопать ваши старые заметки тригонометрии из средней школы! Задача состоит в том, чтобы решить неизвестные стороны и углы разных треугольников. И, как это принято в кодовом гольфе, выигрывает самый маленький рабочий код.

Это не тривиальная проблема; моя эталонная реализация в python в настоящее время сокращена до 838 837 символов, но я уверен, что вы сможете использовать решения для гольфа намного меньше.

Кроме того, если вы застряли, этот раздел Википедии должен помочь вам: Треугольник: Вычисление сторон и углов .

вход

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

Треугольник

Входные данные представлены в виде шести значений, разделенных пробелами, либо stdin качестве аргументов командной строки (на ваш выбор). Шесть значений соответствуют сторонам a, b, cи углам A, B, C. Неизвестные стороны обозначены как вопросительные знаки ( ?). Углы входа и выхода должны быть в радианах. Вы можете предположить, что входные значения верны (вам не нужно ничего проверять). Вы также можете предположить, что входной треугольник невырожден и что все стороны и углы отличны от нуля.

Следующий пример ввод говорит о том , что сторона aявляется 8, сторона bявляется 12и угломA равен 0.5радианам:

8 12 ? 0.5 ? ?

Выход

Выходные данные выдаются в том же формате, что и входные данные - шесть разделенных пробелами чисел включены stdout. Единственное исключение - когда невозможно решить входной треугольник - тогда строка "No solution"должна быть записана в stdout. Если возможны два решения, они оба выводятся с новой строкой между ними.

Ниже приведен вывод для вышеуказанного ввода:

8.0 12.0 16.0899264342 0.5 0.802561439714 1.83903121388
8.0 12.0 4.97205505116 0.5 2.33903121388 0.302561439714

Вывод не обязательно должен иметь большую точность, но требуется как минимум пара десятичных знаков.

правила

  • Входные данные читаются из stdinили аргументы командной строки
  • Вывод записывается в stdout
  • Если с данным входом возможны два решения, выведите оба
  • Если информации слишком мало, чтобы получить одно или два четких решения, рассмотрите "No solution"случай
  • Нельзя использовать встроенный или уже существующий код (конечно, вы можете использовать функции триггера, но не " solveTriangle" или тому подобное)
  • Самый короткий код выигрывает

Контрольные примеры

В   3 4 5 ? ? ?

Вне 3.0 4.0 5.0 0.643501108793 0.927295218002 1.57079630572


В   ? 4 ? 0.64 0.92 1.57

Вне 3.00248479301 4.0 5.02764025486 0.64 0.92 1.57


В   ? ? 5 ? 0.92 ?

Вне No solution


В   ? ? 5 ? 0.92 1.57

Вне 3.03226857833 3.97800936148 5.0 0.65159265359 0.92 1.57


В   8 12 ? 0.5 ? ?

Out (два решения)

8.0 12.0 16.0899264342 0.5 0.802561439714 1.83903121388
8.0 12.0 4.97205505116 0.5 2.33903121388 0.302561439714

В   8 12 ? ? .5 ?

Вне 8.0 12.0 18.3912222133 0.325325285223 0.5 2.31626736837

Удачи!


Можем ли мы предположить, что треугольник невырожден со всеми длинами и углами положительными (в частности, ненулевые)?
Бутл

@ Boothby Да, вы можете. Я обновлю ОП.

1
Также ... если вы хотите, чтобы мы распечатали все решения, вам необходимо предоставить хотя бы одну сторону. В противном случае, знаете, бесконечные решения.
Бутл

@boothby, мне, наверное, здесь было слишком непонятно. Я имел в виду, что если есть два решения для ввода, вы должны вывести оба.

Ответы:


7

Python, 441 символ

from math import*
V=[map(float,raw_input().replace('?','0').split())+[0]]
for i in' '*9:
 W=[]
 for a,b,c,A,B,C,R in V:
  if B and C:A=A or pi-B-C
  if a:
   if A:R=R or a/sin(A)
   else:
    if b and c:A=acos((b*b+c*c-a*a)/2/b/c)
    elif R:N=asin(a/R);W+=[(b,c,a,B,C,N,R)];A=pi-N
  else:a=R*sin(A)
  W+=[(b,c,a,B,C,A,R)]
 V=W
V=[T for T in V if all(t>0 for t in T)]
if V:
 for T in V:print' '.join(map(str,T[:-1]))
else:print'No solution'

Имеет ли ваш типичный триггер для расчета ответа. Текущие возможные решения хранятся в виде кортежей в V. Любые неизвестные значения записываются как 0. Седьмая переменная R является значением a/sin(A)==b/sin(B)==c/sin(C).

Я использую трюк, где значения a / b / c циклически повторяются на каждой итерации, чтобы избежать большого количества избыточной логики. Внутреннему циклу нужно только вычислить значения стороны или угла.


Я использую похожий трюк с циклическим изменением переменных, но вы наверняка победили мое решение. +1, узнал пару новых трюков от этого :)

Кстати, с вашим кодом есть проблема: попробуйте 8 12 ? ? .5 ?.

1
Вы можете получить его до 419 байт, если вы сбрите разрыв задней линии и замените два внутренних отступа одной и двумя вкладками соответственно.
Джои

Ха, это тоже очень похоже на мое решение, хотя я не заметил «все решения», пока вы не опубликовали это. Вы можете сэкономить еще больше , если вы заменяете if aс if not aи придавить вниз условные до 1 -го уровня.
Boothby

4

Обычный C, 565 555 530 символов

Я думаю, C не лучший язык для Code Golf, так что это просто для удовольствия.

float t[6],u[6],P=3.1415;x,w,j,k,D,E;
#define y(V) for(V=0;V<6;++V)
#define Y if(p[j]&&p[k]&&
#define A(o,s,a,b,c,A,B,C) z(float*p){y(D)y(E)if(j=D%3,k=E%3,j-k){Y c)w=C=acos((a*a+b*b-c*c)/2/a/b);if(A&&B)w=C=P-A-B;Y C)w=c=sqrt(a*a+b*b-2*a*b*cos(C));if(A&&B&&a)w=b=s(B)*a/s(A);Y A&&!B&&!C)w=B=(x=A<P/2&&a<b&&p==u,1-2*x)*(asin(b*s(A)/a)-x*P);}y(j)k=w&&(p==t||x>0)&&o("%f ",a);o("\n");}main(int l,char*q[]){y(j)sscanf(*++q,"%f",t+j),u[j]=t[j];z(t);z(u);j=w||o("No solution\n");}
A(printf,sin,p[j],p[k],p[3-j-k],p[j+3],p[k+3],p[6-j-k])

Составлено с cc -o trig trig.c -lm. Читает ввод как аргументы командной строки.


Это решение также не подходит для 8 12 ? ? .5 ?- я добавил его в качестве дополнительного контрольного примера в OP.

1
Исправлена! Длина уменьшена как побочный эффект :)
Александр Бакулин

1

Perl - 412 символов

В качестве perl-однострочника, основанного на Python Solution Кейта Рэндалла:

use Math::Trig;@V=((map{tr/?/0/;$_}@ARGV),0);map{my@W;while(($a,$b,$c,$A,$B,$C,$R)=splice@V,0,7){$A||=pi-$B-$C if($B*$C);if($a){if($A){$R||=$a/sin$A;}else{if($b*$c){$A=acos(($b*$b+$c*$c-$a*$a)/2/$b/$c);}elsif($R){$N=asin($a/$R);push@W,$b,$c,$a,$B,$C,$N,$R;$A=pi-$N;}}}else{$a=$R*sin$A;}push@W,$b,$c,$a,$B,$C,$A,$R if($a*$b*$c>=0);}@V=@W;}(1..9);print($V[0]?join' ',map{(((6-$i++)%7)?$_:"\n")}@V:"No solution\n");

Вот в более читаемой форме:

use Math::Trig;
@V = ( ( map { tr/?/0/; $_ } @ARGV ), 0 );
map {
    my @W;
    while ( ( $a, $b, $c, $A, $B, $C, $R ) = splice @V, 0, 7 ) {
        $A ||= pi- $B - $C
             if ( $B * $C );
        if ($a) {
            if ($A) { $R ||= $a / sin $A; }
            else {
                if ( $b * $c ) {
                    $A = acos(
                        ( $b * $b + $c * $c - $a * $a ) / 2 / $b / $c );
                } elsif ($R) {
                    $N = asin( $a / $R );
                    push @W, $b, $c, $a, $B, $C, $N, $R;
                    $A = pi- $N;
                }
            }
        } else {
            $a = $R * sin $A;
        }
        push @W, $b, $c, $a, $B, $C, $A, $R
            if ( $a * $b * $c >= 0 );
    }
    @V = @W;
} ( 1 .. 9 );

print( $V[0]
         ? join ' ', map { ( ( ( 6 - $i++ ) % 7 ) ? $_ : "\n" ) } @V
         : "No solution\n" );
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.