题目描述
在平面上,每个人都和原点有一定的距离 $ r_i $ ,人与人之间的联系组成了一个多边形,就是这 $ n $ 个人所组成的凸包。凸包上人的顺序随意。
最好的联系,所对应的多边形面积最大,那么这个多边形的面积是多少?
输入格式
第一行一个整数 $n$ 。
接下来一行 $n$ 个整数依次表示 $ r_i $ 。
输出格式
输出一个实数表示答案, 要求绝对误差或相对误差≤$10^{-6}$
样例
input
4
5
8
58
85
output
2970
Sol
拉格朗日乘数法
考虑在$O(N!)$的时间内枚举点的相对位置
则问题转化为 约束为$sum{x_i}=2π$ 求$sum{r_i*r_{i+1}*sin(xi)}$的极限
构造$ F $ = $ sum{r_i*r_{i+1}*sin(x_i)+k*(sum{x_i}-2π)}$
考虑对于每一个$x_i$求偏导数 并且使F的偏导数为0
则可以发现 是联立形如$r_i*r_{i+1}*cos(xi)+k=0$的形式
即联立多个$r_i*r_{i+1}*cos(xi)=t$的形式
然后将这多个方程与$sum{x_i}=2π$联立
可以发现的是所有的$x_i$关于$t$单调 二分一个$t$ 就可以在$O(n log(max( {ri*r_{i+1} ) }))$时间内求解答案
总复杂度$O(n!*n*log(max{r_i*r_{i+1}}))$
Code
#include <bits/stdc++.h> using namespace std; int N,NN; int a[15]; bool used[1005]; double ans,pi=acos(-1.0); double r[1005]; const double eps=1e-7; double Check(double Now){ double ret=0.0; for (int i=1;i<=N;i++) ret=ret+acos(Now/r[a[i]]/r[a[i+1]]); return ret; } double calc(){ double l,rr=1e7; a[N+1]=a[1]; for (int i=1;i<=N;i++) rr=min(rr,r[a[i]]*r[a[i+1]]); l=-rr; while (rr-l>eps){ double mid=(l+rr)/2.0; if (Check(mid)<2.0*pi) rr=mid; else l=mid; } if (Check(l)-2.0*pi>eps) return 0; double Ans=0.0; for (int i=1;i<=N;i++) Ans+=r[a[i]]*r[a[i+1]]*sin(acos(l/r[a[i]]/r[a[i+1]])); return Ans; } void dfs(int Len){ if (Len>3) { a[Len]=a[1]; N=Len-1; ans=max(ans,calc()); } if (Len>NN) return; for (int i=1;i<=NN;i++) if (!used[i]){ used[i]=true; a[Len]=i; dfs(Len+1); used[i]=false; } } int main(){ scanf("%d",&N); NN=N; for (int i=1;i<=N;i++) cin>>r[i]; dfs(1); printf("%.8lf ",ans/2.0); return 0; }