題面
Time limit per test: 2 seconds
Memory limit per test: 256 megabytes
Description
You are given a regular polygon with 2⋅n vertices (it's convex and has equal sides and equal angles) and all its sides have length 1. Let's name it as 2n-gon.
Your task is to find the square of the minimum size such that you can embed 2n-gon in the square. Embedding 2n-gon in the square means that you need to place 2n-gon in the square in such way that each point which lies inside or on a border of 2n-gon should also lie inside or on a border of the square.
You can rotate 2n-gon and/or the square.
Input
The first line contains a single integer T (1≤T≤200) — the number of test cases.
Next T lines contain descriptions of test cases — one per line. Each line contains single odd integer n (3≤n≤199). Don't forget you need to embed 2n-gon, not an n-gon.
Output
Print T real numbers — one per test case. For each test case, print the minimum length of a side of the square 2n-gon can be embedded in. Your answer will be considered correct if its absolute or relative error doesn't exceed 10−6.
Example
input
3
3
5
199
output
1.931851653
3.196226611
126.687663595
題意
給定一個邊長為 1 的正 2n 邊形
求外接正方形的最小面積
解題思路
因為本題給定的 n 是奇數
又因為外接正方形要求面積最小
所以不會有邊與正方形重合,只存在四個點會位於外接正方形的四條邊上
以正十邊形為例

外接正方形的作圖方法為
選擇一對 連線能夠通過正十邊形中心點 的點對,連接兩點,並向兩端延長
然后從正十邊形中心點開始作垂直於前面那條邊的邊,並向兩端延長
然后以這兩條線為准作一個斜45°正方形
為將正方形縮小到最小,所以要保證正十邊形上有點會落在正方形上
故作出來的圖如上圖所示
具體作圖法放在了文章末尾
只看其四分之一部分

首先可以通過 360°/(2*n) 來求出每份角的角度 ang
因為邊長為 1 ,所以可以通過一個頂角為 ang ,底邊為 1 的等腰三角形來求出腰長 x = 0.5/sin(ang/2)
因為總共有 10 個角,所以在四分之一圖中平均有 10/4 = 2.5個角
因為這些正多邊形都是凸多邊形,所以與正方形的交點一定是最接近於中間位置的那個點 (文章末尾也會解釋這一點)
所以實際的 θ = round(2.5/2)*ang
公式里表示為 ang2 = round(n/4)*ang
對於ans1,根據正弦定理
可以得到 ans1 / sinθ = x / sin45°
得到 ans1 = x / sin45° * sinθ
對於ans2,根據正弦定理
可以得到 ans2 / sin(90°-θ) = x / sin45°
得到 ans2 = x / sin45° * sin(90°-θ)
相加即為正方形邊長
完整程序
#include<bits/stdc++.h>
using namespace std;
const double PI=acos(-1.0);
const double epsilon=PI/180.0; //角度轉弧度
void solve()
{
int n;
cin>>n;
double ang=180.0/n;
double ang2=round(n/4.0)*ang;
double x=1.0/(2.0*sin(ang/2.0*epsilon));
double ans1=x/sin(45.0*epsilon)*sin(ang2*epsilon);
double ans2=x/sin(45.0*epsilon)*sin((90.0-ang2)*epsilon);
cout<<fixed<<setprecision(9)<<ans1+ans2<<'\n';
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
int T;cin>>T;
while(T--)
solve();
return 0;
}
關於作圖 - 最優作圖法的證明
主要參考了 《正四邊形內接正六邊形》 才獲得靈感
在不計數值的情況下,可以將正多邊形外接最小正四邊形轉成正四邊形內接最大正多邊形的畫法
因為正多邊形一定保證所有邊都位於一個圓心即正多邊形中心的圓上
所以可以從作最大可能的圓入手
以正六邊形為例
先畫出一個正方形,連接對角線找出中點

再選擇其中一條對角線,每次繞中點旋轉正多邊形的單位角 θ ,旋轉半圈
由於是正六邊形,故將 360° 平分 6 份,每份 60°
所以每次旋轉 60°,畫圖

此時可以發現,加上對角線后得到的三條線
恰好與正方形交於 6 個點
故內接最大正六邊形每個頂點都會落於這三條邊上
為了使得內接正六邊形最大,又因為正多邊形每個頂點都會落在一個圓上
所以需要畫出最大可能的圓
所以在畫出的六個頂點中找出離中點最近的一個點
並以中點為圓心,中點到這個點的距離為半徑畫圓

這個圓也許會超出正方形的邊界,但可以保證正多邊形在正方形內(因為選擇的是離中點最近的點,所以與每條邊的交點都在正方形內或正方形邊界上)
最后,這個圓交三條線與六個點,連接后即獲得內接最大正六邊形

所以在思路部分(將上圖旋轉45°)
需要選取四分之一圖中最接近中心的點來算得 ang2
也就是 round(n/4.0)*ang 的由來
這是因為距離正方形中心最近的點一定也距離正方形的邊的中點最近
