Temukan luas poligon


9

Dengan panjang sisi berurutan s1, s2, s3... s_nn-gon yang tertulis dalam lingkaran, temukan luasnya. Anda dapat mengasumsikan bahwa poligon itu ada. Selain itu, poligon akan menjadi cembung dan tidak berpotongan sendiri, yang cukup untuk menjamin keunikan. Built-in yang secara khusus mengatasi tantangan ini, serta fungsi built-in yang menghitung circumradius atau circumcenter, dilarang (ini berbeda dari versi sebelumnya dari tantangan ini).

Input: Panjang sisi poligon siklik; dapat diambil sebagai parameter ke suatu fungsi, stdin, dll.

Output: Area poligon.

Jawabannya harus akurat hingga 6 desimal dan harus berjalan dalam 20 detik pada laptop yang masuk akal.

Ini golf kode sehingga kode terpendek menang!

Kasus uji khusus:

[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

Generator test case:


7
Saya tahu cara mudah untuk menemukan batasnya.
— mIllIbyte

1
Saya tahu cara mudah untuk menemukan jumlah sisi
— Luis Mendo

Masalah ini cukup mudah mengingat circumradius, tetapi tanpanya sangat sulit.
— poi830

Ini juga mudah jika ada kurang dari lima sisi, bukan itu penting dalam kode golf.
— Neil

Jawaban:


5

Python 2, 191 byte

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

Menggunakan pencarian biner untuk menemukan jari-jari, kemudian menghitung luas setiap segmen berdasarkan sudut / jari-jari.

Ia menemukan jari-jari dengan pertama-tama menjumlahkan semua kecuali sudut akor terbesar, dan memeriksa sudut yang tersisa ke akor yang tersisa. Sudut-sudut itu kemudian juga digunakan untuk menghitung luas setiap segmen. Area segmen bisa negatif, jika sudutnya lebih besar dari 180 derajat.

Implementasi yang mudah dibaca:

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

Apakah ini berfungsi jika pusat berada di luar poligon? (Misalnya, segitiga dengan panjang sisi 6, 7, 12). Terkadang sqrt(4**2 - c**2/4)kebutuhan menjadi negatif, ketika sudut lebih besar dari pi.
— soktinpk

@soktinpk saya memperbaiki jawaban saya.
— orlp

0

Oktaf, 89 byte

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

Penjelasan

Sudut amembentang oleh segmen panjang sadalah 2*asin(s/2/r), diberikan circumradius sebuah r. Daerahnya adalah cos(a)*s/2*r.

Algoritma

  1. Set r ke sesuatu yang terlalu besar, seperti perimeter.
  2. Jika sudut terakumulasi lebih kecil dari 2pi, kurangi rdan ulangi langkah 2.
  3. Hitung area.

Rata-rata, berapa banyak iterasi yang diperlukan untuk rditetapkan? (penasaran)
— soktinpk

Tidak mungkin ini memiliki ketelitian yang dibutuhkan. Anda berulang kali mengalikan jari-jari dengan 0,9999 untuk menguranginya, ini membuatnya sangat mudah untuk menurunkan 6 desimal yang diperlukan.
— orlp

@soktinpk sekitar 15000 untuk r*=1-1e-4dan 150000 untuk r*=1-1e-5.
— Rainer P.

@RainerP. Kedua nilai itu sama.
— Dana Gugatan Monica

1
@soktinpk pada umumnya bukan ide yang baik untuk membuat pengecualian untuk jawaban tertentu.
— Cyoce
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.