Çokgenin alanını bulma


9

s1, s2, s3... s_nBir daire içine yazılan bir n-gon'un ardışık yan uzunlukları göz önüne alındığında , alanını bulun. Çokgenin var olduğunu varsayabilirsiniz. Ek olarak, çokgen dışbükey olacak ve kendi kendine kesişmeyecek, bu da benzersizliği garanti etmek için yeterli olacaktır. Bu zorluğu özel olarak çözen yerleşiklerin yanı sıra, çember veya çevreyi hesaplayan yerleşik işlevler de yasaklanmıştır (bu, bu zorluğun önceki bir sürümünden farklıdır).

Girdi: Döngüsel çokgenin yan uzunlukları; bir fonksiyona, stdin'e vb. parametre olarak alınabilir.

Çıktı: Çokgenin alanı.

Cevap 6 ondalık basamağa kadar doğru olmalı ve makul bir dizüstü bilgisayarda 20 saniye içinde çalışmalıdır.

Bu kod golf çok kısa kod kazanır!

Özel test durumları:

[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

Test kutusu üreteci:


7
Çevresini bulmanın kolay bir yolunu biliyorum.
mIllIbyte

1
Taraf sayısını bulmanın kolay bir yolunu biliyorum
Luis Mendo

Bu sorun, çember göz önüne alındığında oldukça kolaydır, ancak onsuz inanılmaz derecede zordur.
poi830

Beşten daha az taraf varsa da kolaydır, kod golfünde önemli değildir.
Neil

Yanıtlar:


5

Python 2, 191 bayt

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

Yarıçapı bulmak için bir ikili arama kullanır, ardından her parçanın alanını açı / yarıçap ile hesaplar.

Yarıçapı önce en büyük akor açısı hariç tümünü toplayarak ve kalan akorun kalan açısını kontrol ederek bulur. Bu açılar daha sonra her bir segmentin alanını hesaplamak için de kullanılır. Bir bölümün alanı, açısı 180 dereceden büyükse negatif olabilir.

Okunabilir uygulama:

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

Merkez çokgenin dışındaysa bu işe yarar mı? (Örneğin, kenar uzunlukları 6, 7, 12 olan bir üçgen). Bazen sqrt(4**2 - c**2/4)açı daha büyük olduğunda negatif olması gerekir pi.
soktinpk

@soktinpk Cevabımı düzelttim.
orlp

0

Oktav, 89 bayt

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çıklama

Açı auzunlukta bir parça tarafından yayılmış solan 2*asin(s/2/r), bir circumradius verilen r. Alanı cos(a)*s/2*r.

Algoritma

  1. rÇevre gibi çok büyük bir şeye ayarlayın .
  2. Toplanan açı daha küçükse 2pi, r2. adımı azaltın ve tekrarlayın.
  3. Alanı hesaplayın.

Ortalama olarak, bunun kaç kez tekrarlanması rgerekiyor? (meraktan)
soktinpk

Bunun gereken hassasiyete sahip olması mümkün değildir. Yarıçapı azaltmak için tekrar tekrar 0,99999 ile çarpıyorsunuz, bu da gerekli 6 ondalık kesinlik değerini aşmayı çok kolaylaştırıyor.
orlp

@soktinpk için 15000 r*=1-1e-4ve 150000 için r*=1-1e-5.
Rainer P.16

@RainerP. Bu iki değer aynı.
Monica'nın Davası

1
Belirli bir cevap için istisna yapmak genellikle iyi bir fikir değildir.
Cyoce
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.