Знайдіть площу багатокутника


9

Враховуючи послідовні бічні довжини s1, s2, s3... s_nn-гона, вписаного у коло, знайдіть його площу. Ви можете припустити, що багатокутник існує. Крім того, багатокутник буде опуклим і не перетинається, що достатньо, щоб гарантувати унікальність. Вбудовані модулі, які спеціально вирішують цю проблему, а також вбудовані функції, які обчислюють окружність або окружність, заборонені (це відрізняється від попередньої версії цього виклику).

Введення: бічні довжини циклічного багатокутника; може сприйматися як параметри функції, stdin тощо.

Вихід: Площа багатокутника.

Відповідь повинна бути точною до 6 знаків після коми і повинна працювати протягом 20 секунд на розумному ноутбуці.

Це код гольфу, тому найкоротший виграш коду!

Конкретні тестові випадки:

[3, 4, 5] --> 6
[3, 4, 6] --> 5.332682251925386
[3, 4, 6, 7] --> 22.44994432064365
[5, 5, 5, 5] --> 25
[6, 6, 6, 6, 6] --> 61.93718642120281
[6.974973020933265, 2.2393294197257387, 5.158285083300981, 1.4845682771595603, 3.5957940796134173] --> 21.958390804292847
[7.353566082457831, 12.271766915518073, 8.453884922273897, 9.879017670784675, 9.493366404245332, 1.2050010402321778] --> 162.27641678140589

Генератор тестових випадків:


7
Я знаю простий спосіб знайти його периметр.
— mIllIbyte

1
Я знаю простий спосіб знайти кількість сторін
— Луїс Мендо

Ця проблема досить проста, враховуючи окружність, але без неї неймовірно складно.
— poi830

Це також легко, якщо менше п'яти сторін, не те, що це має значення в коді гольфу.
— Ніл

Відповіді:


5

Пітон 2, 191 байт

from math import*
C=sorted(input());l,h=C[-1]/2,sum(C)
while h-l>1e-9:m=l+h;a=[asin(c/m)for c in C[:-1]];f=pi-sum(a);l,h=[l,m/2,h][m*sin(f)<C[-1]:][:2]
print sum(l*l*sin(2*t)for t in a+[f])/2

Використовує двійковий пошук, щоб знайти радіус, а потім обчислює площу кожного сегмента за кутом / радіусом.

Він знаходить радіус, спочатку підсумовуючи всі, крім найбільшого кута акорда, і перевіряючи кут, що залишився, до залишку акорда. Ці кути також використовуються для обчислення площі кожного сегмента. Площа сегмента може бути негативною, якщо її кут перевищує 180 градусів.

Читальна реалізація:

import math

def segment_angles(line_segments, r):
    return [2*math.asin(c/(2*r)) for c in line_segments]

def cyclic_ngon_area(line_segments):
    line_segments = list(sorted(line_segments))
    lo, hi = max(line_segments) / 2, sum(line_segments)
    while hi - lo > 1e-9:
        mid = (lo + hi) / 2
        angles = segment_angles(line_segments[:-1], mid)
        angles.append(2*math.pi - sum(angles))
        if 2 * mid * math.sin(angles[-1]/2) < line_segments[-1]:
            lo = mid
        else:
            hi = mid
    return sum([lo*lo * math.sin(a) / 2 for a in angles])

Чи працює це, якщо центр знаходиться поза полігоном? (Наприклад, трикутник зі сторонами довжини 6, 7, 12). Іноді sqrt(4**2 - c**2/4)потреба повинна бути негативною, коли кут більший за pi.
— соктінпк

@soktinpk я виправив свою відповідь.
— orlp

0

Октава, 89 байт

r=sum(s=input(''));while sum(a=asin(s/2/r))<pi r*=1-1e-4;b=a;end;disp(sum(cos(b).*s/2*r))

Пояснення

Кут , aнатягнуте на відрізку довжини sє 2*asin(s/2/r), дається описаної окружності r. Його площа єcos(a)*s/2*r .

Алгоритм

  1. Встановити r щось занадто велике, наприклад периметр.
  2. Якщо кутовий кут менший за 2pi, зменшітьr і повторіть крок 2.
  3. Обчисліть площу.

У середньому, скільки повторень rпотрібно встановити? (з цікавості)
— soktinpk

Ні в якому разі це не має необхідної точності. Ви багаторазово множите радіус на 0,9999, щоб зменшити його, це дуже легко підкреслить необхідні 6 десятків точності.
— orlp

@soktinpk близько 15000 за r*=1-1e-4та 150000 за r*=1-1e-5.
— Райнер П.

@RainerP. Ці два значення однакові.
— Фонд позову Моніки

1
@soktinpk, як правило, не годиться робити виняток для конкретної відповіді.
— Cyoce
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.