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


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.