Biorąc pod uwagę kolejne długości boku s1, s2, s3... s_n
n-gonu wpisanego w okrąg, znajdź jego obszar. Możesz założyć, że wielokąt istnieje. Ponadto wielokąt będzie wypukły i nie będzie się przecinał, co wystarczy, aby zagwarantować wyjątkowość. Wbudowane rozwiązania, które konkretnie rozwiązują to wyzwanie, a także wbudowane funkcje, które obliczają obwód lub okrążenie, są zakazane (różni się to od poprzedniej wersji tego wyzwania).
Dane wejściowe: długości boków wielokąta cyklicznego; mogą być brane jako parametry funkcji, standardu itp.
Dane wyjściowe: obszar wielokąta.
Odpowiedź powinna być dokładna do 6 miejsc po przecinku i musi zostać uruchomiona w ciągu 20 sekund na rozsądnym laptopie.
To jest golf golfowy, więc wygrywa najkrótszy kod!
Konkretne przypadki testowe:
[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 przypadków testowych:
function randPolygon(n) {
var left = 2 * Math.PI;
var angles = [];
for (var i = 0; i < n - 1; ++i) {
var r = Math.random() * left;
angles.push(r);
left -= r;
}
angles.push(left);
var area = 0;
var radius = 1 + Math.random() * 9;
for (var i = 0; i < angles.length; ++i) area += radius * radius * Math.sin(angles[i]) / 2;
var sideLens = angles.map(function(a) {
return Math.sin(a / 2) * radius * 2;
});
document.querySelector("#radius").innerHTML = radius;
document.querySelector("#angles").innerHTML = "[" + angles.join(", ") + "]";
document.querySelector("#inp").innerHTML = "[" + sideLens.join(", ") + "]";
document.querySelector("#out").innerHTML = area;
draw(angles);
}
function draw(angles) {
var canv = document.querySelector("#diagram"),
ctx = canv.getContext("2d");
var size = canv.width
ctx.clearRect(0, 0, size, size);
ctx.beginPath();
ctx.arc(size / 2, size / 2, size / 2, 0, 2 * Math.PI, true);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(size, size / 2);
var runningTotal = 0;
for (var i = 0; i < angles.length; ++i) {
runningTotal += angles[i];
var x = Math.cos(runningTotal) * size / 2 + size / 2;
var y = Math.sin(runningTotal) * size / 2 + size / 2;
ctx.lineTo(x, y);
}
ctx.stroke();
}
document.querySelector("#gen").onclick = function() {
randPolygon(parseInt(document.querySelector("#sideLens").value, 10));
}
<div id="hints">
<p><strong>These are to help you; they are not part of the input or output.</strong>
</p>
Circumradius:
<pre id="radius"></pre>
Angles, in radians, of each sector (this are NOT the angles of the polygon):
<pre id="angles"></pre>
</div>
<hr>
<div id="output">
Input:
<pre id="inp"></pre>
Output:
<pre id="out"></pre>
</div>
<hr>
<div id="draw">
Diagram:
<br />
<canvas id="diagram" width="200" height="200" style="border:1px solid black"></canvas>
</div>
Number of side lengths:
<input type="number" id="sideLens" step="1" min="3" value="3" />
<br />
<button id="gen">Generate test case</button>
Odpowiedzi:
Python 2, 191 bajtów
Korzysta z wyszukiwania binarnego, aby znaleźć promień, a następnie oblicza powierzchnię każdego segmentu na podstawie kąta / promienia.
Wyszukuje promień, najpierw sumując wszystko oprócz największego kąta cięciwy i sprawdzając pozostały kąt do pozostałego cięciwy. Kąty te są następnie wykorzystywane również do obliczania powierzchni każdego segmentu. Pole segmentu może być ujemne, jeśli jego kąt jest większy niż 180 stopni.
Czytelne wdrożenie:
źródło
sqrt(4**2 - c**2/4)
musi być ujemna, gdy kąt jest większy niżpi
.Oktawa, 89 bajtów
Wyjaśnienie
Kąt
a
rozpięty o odcinek długościs
jest2*asin(s/2/r)
podany wokół obwodur
. Jego powierzchnia tocos(a)*s/2*r
.Algorytm
r
na coś zbyt dużego, na przykład na obwód.2pi
, zmniejszr
i powtórz krok 2.źródło
r
trzeba ustawić iteracji ? (z ciekawości)r*=1-1e-4
i 150000 forr*=1-1e-5
.