【NOI2018模拟3.27】Yja

Description

在平面上找 n 个点, 要求这 n 个点离原点的距离分别为 r 1 ,r 2 ,…,r n . 最大化这 n 个点构成的凸包面积, 凸包上的点的顺序任意.不要求点全部在凸包上
n<=8

Solution

玄学几何题其实并不是
枚举点是否出现和一个顺序,问题变成求

max(12i=1nr[i]r[imodn+1]sin(θi))

限制是:
i=1nθi=2π

然后有一个叫拉格朗日乘数的东西,可以做这个式子的极值。
设一个拉格朗日乘数 λ ,极值函数为f(x1,x2..xn),限制函数为g(x1,x2..xn)=c
那么将目标函数改造为F(x1,x2…xn, λ )=f(x1,x2..xn)+ λ (g(x1,x2…xn)-c)
然后对该函数做偏导,每一个变量xi处的偏导为0
这样就可以得到n个方程,足以解出n个变量。
回到这道题,我们可以发现最后偏导出来的结果形如 r[i]r[imodn+1]cos(θi)+λ=0
对于每一项都成立,并且我们知道 θi [0,π] 范围内是递减的,于是我们可以二分这个 λ ,然后把所有的 θ 求出来。
但是注意有一个细节,你求出来的某个 θ 可能趋于0,这个时候需要舍去这种情况
别问我我也不知道为什么

Code

#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;

typedef double db;

const db pi=acos(-1);
const db eps=1e-4;

int n,lim,r[10],R[10];
bool vis[10];
db theta[10],ans;

bool check(db x) {
    fo(i,1,lim) theta[i]=acos(x*1.0/R[i]/R[i%lim+1]);
    db all=0;fo(i,1,lim) all+=theta[i];
    return all>2*pi;
}

void dfs(int x) {
    if (x>lim) {
        int mn=1e6;
        fo(i,1,lim) mn=min(mn,R[i]*R[i%lim+1]);
        db le=-mn,ri=mn;
        while (ri-le>eps) {
            db mid=(le+ri)*0.5;
            if (check(mid)) le=mid;
            else ri=mid;
        }
        fo(i,1,lim) if (theta[i]<eps) return;
        db res=0;
        fo(i,1,lim) res+=R[i]*R[i%lim+1]*sin(theta[i]);
        ans=max(ans,res/2.0);
        return;
    }
    fo(i,1,n)
        if (!vis[i]) {
            R[x]=r[i];vis[i]=1;
            dfs(x+1);
            R[x]=0;vis[i]=0;
        }
}

int main() {
    freopen("yja.in","r",stdin);
    freopen("yja.out","w",stdout);
    scanf("%d",&n);
    fo(i,1,n) scanf("%d",&r[i]);
    fo(i,3,n) {
        lim=i;
        dfs(1);
    }
    printf("%.8lf\n",ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值