ค้นหาพื้นที่ของรูปหลายเหลี่ยม


9

เมื่อให้ความยาวด้านต่อเนื่องs1, s2, s3... s_nของ n-gon ที่ถูกจารึกไว้ในวงกลมให้หาพื้นที่ของมัน คุณอาจคิดว่ามีรูปหลายเหลี่ยมอยู่ นอกจากนี้รูปหลายเหลี่ยมจะนูนและไม่ตัดกันเองซึ่งเพียงพอที่จะรับประกันเอกลักษณ์ บิวด์อินที่แก้ปัญหาความท้าทายนี้โดยเฉพาะรวมถึงฟังก์ชั่นในตัวที่คำนวณค่า circumradius หรือ circumcenter นั้นถูกแบน (สิ่งนี้แตกต่างจากเวอร์ชั่นก่อนหน้าของความท้าทายนี้)

อินพุต: ความยาวด้านของรูปหลายเหลี่ยมแบบวงกลม อาจถูกใช้เป็นพารามิเตอร์ของฟังก์ชัน 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
ฉันรู้วิธีง่ายๆในการค้นหาจำนวนด้าน
Luis Mendo

ปัญหานี้เป็นเรื่องง่ายที่จะได้รับ circumradius แต่ถ้าไม่มีมันก็ยากอย่างไม่น่าเชื่อ
poi830

นอกจากนี้ยังง่ายถ้ามีน้อยกว่าห้าด้านไม่ใช่เรื่องสำคัญในการตีกอล์ฟ
Neil

คำตอบ:


5

Python 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

@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)ได้รับ rcircumradius 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สำหรับ
Rainer P.

@RainerP ค่าทั้งสองนั้นเหมือนกัน
คดีฟ้องร้องกองทุนโมนิก้า

1
@soktinpk โดยทั่วไปแล้วไม่ใช่ความคิดที่ดีที่จะยกเว้นสำหรับคำตอบเฉพาะ
Cyoce
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.