Dado o comprimento lateral consecutivo s1, s2, s3... s_n
de um n-gon inscrito em um círculo, encontre sua área. Você pode assumir que o polígono existe. Além disso, o polígono será convexo e não se entrecruzará, o que é suficiente para garantir a exclusividade. Os internos que resolvem especificamente esse desafio, bem como as funções internas que calculam o perímetro ou o perímetro, são banidos (isso é diferente da versão anterior deste desafio).
Entrada: os comprimentos laterais do polígono cíclico; podem ser tomados como parâmetros para uma função, stdin, etc.
Saída: a área do polígono.
A resposta deve ter precisão de 6 casas decimais e deve ser executada em 20 segundos em um laptop razoável.
Este é o código de golfe, então o código mais curto vence!
Casos de teste específicos:
[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
Gerador de caso de teste:
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>
Respostas:
Python 2, 191 bytes
Utiliza uma pesquisa binária para encontrar o raio e calcula a área de cada segmento pelo ângulo / raio.
Ele encontra o raio somando primeiro todos os ângulos, exceto o maior ângulo da corda, e verificando o ângulo restante da corda restante. Esses ângulos também são usados para calcular a área de cada segmento. A área de um segmento pode ser negativa, se o ângulo for maior que 180 graus.
Implementação legível:
fonte
sqrt(4**2 - c**2/4)
precisa ser negativo, quando o ângulo é maior quepi
.Oitava, 89 bytes
Explicação
O ângulo
a
medido por um segmento de comprimentos
é2*asin(s/2/r)
, dado um perímetror
. Sua área écos(a)*s/2*r
.Algoritmo
r
para algo muito grande, como o perímetro.2pi
, reduzar
e repita a etapa 2.fonte
r
serem definidas? (por curiosidade)r*=1-1e-4
e 150000 parar*=1-1e-5
.