对于只有一个自变量的单峰函数我们可以三分解决。
当然我们也可以求导数然后二分也行(只要你导得出来)
但是对于多个自变量,莫非三分套三分?
套两三个或许可以。
但是我们可以用偏导一次解方程(其实也是二分答案)求出最值(前提是只有一个极值点且你能求偏导)
这就是拉格朗日乘数法。
具体来讲就是你需要求最值的函数是一个山峰,
这个山峰的高度即为函数值,我们可以画出等高线(所以地理在某种程度上算理科)
而这个函数中自变量之间的限制关系画出了一条登山路线,你求的最值即是在路线上的最高点。
你的路线是一条平滑的可求偏导的曲线(不然用什么导数),
然后你仔细想一下,你路线上的最高点所属的等高线(也应该是一条平滑可求偏导的曲线)应该是和你的路线相切的!
然后。。。。。。度娘吧。
在平面上找 n 个点, 要求这 n 个点离原点的距离分别为 r1; r2; :::; rn. 最大化这 n 个点构成的
凸包面积, 凸包上的点的顺序任意
n<=8
枚举点的顺序(可能有一些点用不着)然后就是求关于n个夹角的函数的最值。
这个很好求导吧。
lambda = r1 * r2 * cos sita1 = r2 * r3 * cos sita2 ..........
sita1 + .....sita n =2 PI
lambda 和sita之间有单调性所以可以二分
code:
/*
Lagrange Multiplier
F(x,y,Lambda) = f(x,y) + λ* φ( x,y )
*/
#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#include<iomanip>
#include<iostream>
#include<cmath>
#define maxn 10
#define eps 1e-12
#define PI 3.1415926535897932384626433832795
#define double long double
using namespace std;
int n;
double l[maxn];
int seq[maxn],vis[maxn];
double ans=0;
bool check2(double lambda,int n)
{
double sita=0,tmp;
for(int i=1;i<=n;i++)
{
tmp=acos(lambda / l[seq[i]] / l[seq[i%n+1]]);
sita+=tmp;
}
return sita>=2*PI;
}
void check(int n)
{
double Min=0x3f3f3f3f;
for(int i=1;i<=n;i++) Min=min(Min,l[seq[i]]*l[seq[i%n+1]]);
double L=-Min,R=Min,Mid;
for(;L<R-eps;)
{
Mid=(L+R)*0.5;
if(check2(Mid,n)) L=Mid;
else R=Mid;
}
if(!check2(L,n)) return;
double tmp,ret=0;
for(int i=1;i<=n;i++)
{
tmp=acos(L / l[seq[i]] / l[seq[i%n+1]]);
ret+=l[seq[i]]*l[seq[i%n+1]]*sin(tmp)*0.5;
}
ans=max(ans,ret);
}
void dfs(int k)
{
if(k>1)
check(k-1);
for(int i=1;i<=n;i++)
if(!vis[i])
{
vis[seq[k]=i]=1;
dfs(k+1);
vis[i]=0;
}
}
int main()
{
freopen("yja.in","r",stdin);
scanf("%d",&n);
for(int i=1;i<=n;i++) cin>>l[i];
dfs(1);
cout<<setprecision(20)<<ans;
}