19_05_01校内训练[polygon]

题意

把一个边长为1的正n边形放到一个正m边形中,要求m边形完全覆盖n边形,可以有交点,并且中心重合。求正m边形的最小边长,至少精确到6位。要求logn计算。


思考

先考虑m|n的情况。

我们知道,正m边形的边长与可行区域(即可以完全覆盖的那些角度)形成单射,当且仅当所有可行区域都成为可数的点时,答案最优。(可以理解为再缩小一点就无解了)

这样不难证明,把正n边形的几条边刚好卡在正m边形上是最优的。如n=8,m=4:

这时正m边形的边长是容易计算的。相信大家都会初中数学。

这样再考虑一般情况。由于是中心重合,正n边形旋转2π/m度后仍然是能被覆盖的。

在所有可行的旋转过程中,将最外圈的点连起来,仍然形成一个正多边形,且边数为lcm(n,m)。

例如,n=4,m=6:

用紫线围出来的正12边形即为正方形得到的结果。

至于正确性,在于所有的可行区域都是单点。

这样一来,就可以直接转化为上一个问题。公式认真推即可。


代码

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long int ll;
 4 const double pi=acos(-1);
 5 ll n,m;
 6 ll gcd(ll x,ll y)
 7 {
 8     return x%y==0?y:gcd(y,x%y);
 9 }
10 ll lcm(ll x,ll y)
11 {
12     return x/gcd(x,y)*y;
13 }
14 double solve(ll n,ll m)
15 {
16     double len=1/(2*tan(pi/n));
17     double th=(n/m)*pi/n;
18     return tan(th)*len*2;
19 }
20 int main()
21 {
22     ios::sync_with_stdio(false);
23     cin>>n>>m;
24     double len=1/(2*sin(pi/n));
25     n=lcm(n,m);
26     double a=sin(pi/n)*len*2;
27     cout<<fixed<<setprecision(9)<<solve(n,m)*a<<endl;
28     return 0;
29 }
View Code

猜你喜欢

转载自www.cnblogs.com/GreenDuck/p/10799543.html