Tìm diện tích của một đa giác


9

Cho các chiều dài cạnh liên tiếp s1, s2, s3... s_ncủa một n-gon được ghi trong một vòng tròn, tìm diện tích của nó. Bạn có thể cho rằng đa giác tồn tại. Ngoài ra, đa giác sẽ lồi và không tự giao nhau, điều này đủ để đảm bảo tính duy nhất. Các phần tử tích hợp đặc biệt giải quyết thách thức này, cũng như các hàm tích hợp tính toán chu vi hoặc chu vi, đều bị cấm (điều này khác với phiên bản trước của thử thách này).

Đầu vào: Độ dài cạnh của đa giác tuần hoàn; có thể được lấy làm tham số cho hàm, stdin, v.v.

Đầu ra: Diện tích của đa giác.

Câu trả lời phải chính xác đến 6 chữ số thập phân và phải chạy trong vòng 20 giây trên một máy tính xách tay hợp lý.

Đây là mã golf nên mã ngắn nhất sẽ thắng!

Các trường hợp thử nghiệm cụ thể:

[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

Trình tạo trường hợp thử nghiệm:


7
Tôi biết một cách dễ dàng để tìm chu vi của nó.
mIllIbyte

1
Tôi biết một cách dễ dàng để tìm số bên
Luis Mendo

Vấn đề này khá dễ dàng khi đưa ra chu vi, nhưng không có nó thì cực kỳ khó khăn.
poi830

Cũng dễ dàng nếu có ít hơn năm mặt, không phải là vấn đề trong môn đánh gôn.
Neil

Câu trả lời:


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

Sử dụng tìm kiếm nhị phân để tìm bán kính, sau đó tính diện tích của từng đoạn theo góc / bán kính.

Nó tìm thấy bán kính bằng cách đầu tiên tổng hợp tất cả trừ góc hợp âm lớn nhất và kiểm tra góc còn lại với hợp âm còn lại. Những góc đó sau đó cũng được sử dụng để tính diện tích của từng đoạn. Diện tích của một đoạn có thể âm, nếu góc của nó lớn hơn 180 độ.

Thực hiện có thể đọc được:

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

Điều này có hoạt động nếu trung tâm nằm ngoài đa giác? (Ví dụ: một hình tam giác có cạnh dài 6, 7, 12). Đôi khi sqrt(4**2 - c**2/4)cần phải âm, khi góc lớn hơn pi.
soktinpk

@soktinpk Tôi đã sửa câu trả lời của mình.
orlp

0

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

Giải trình

Các góc được akéo dài bởi một đoạn có chiều dài s2*asin(s/2/r), cho một chu vi r. Diện tích của nó là cos(a)*s/2*r.

Thuật toán

  1. Đặt rthành một cái gì đó quá lớn, chẳng hạn như chu vi.
  2. Nếu góc tích lũy nhỏ hơn 2pi, giảm rvà lặp lại bước 2.
  3. Tính diện tích.

Trung bình, có bao nhiêu lần lặp này rđể thiết lập? (vì tò mò)
soktinpk

Không có cách này có độ chính xác cần thiết. Bạn liên tục nhân bán kính với 0,9999 để giảm nó, điều này giúp bạn dễ dàng tháo gỡ 6 số thập phân chính xác cần thiết.
orlp

@soktinpk khoảng 15000 cho r*=1-1e-4và 150000 cho r*=1-1e-5.
Rainer P.

@RainerP. Hai giá trị đó là như nhau.
Vụ kiện của Quỹ Monica

1
@soktinpk nói chung không phải là một ý tưởng tốt để tạo một ngoại lệ cho một câu trả lời cụ thể.
Cyoce
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.