zoukankan      html  css  js  c++  java
  • 某考试 T2 yja

    2.1 Description

    在平面上找 n 个点, 要求这 n 个点离原点的距离分别为 r1, r2, ..., rn.

    最大化这 n 个点构成的凸包面积, 凸包上的点的顺序任意.

    2.2 Input Format

    第一行一个整数 n.

    接下来一行 n 个整数依次表示 ri .

    2.3 Output Format

    输出一个实数表示答案, 要求绝对误差或相对误差 ≤ 10−6.

    2.4 Sample

    2.4.1 Input

    4

    5

    8

    58

    85

    2.4.2 Output

    2970

    2.5 Constraints

    对于前 20% 的数据, n ≤ 3;

    对于前 40% 的数据, n ≤ 4;

    对于另 20% 的数据, r1 = r2 = ... = rn;

    对于 100% 的数据, 1 ≤ n ≤ 8, 1 ≤ ri ≤ 1000.

        考试的时候看了一会题就感觉是个拉格朗日乘数法的题,但是我为什么往叉积求面积上想了23333,于是就出来了n个限制然后还得三分套三分套三分.......

    于是在想如何优化求偏导都是零的过程中时间过去了2.5h  。。。(我好菜啊我现在退役算了)。

        正解其实就是拉格朗日乘数法,但是求面积是用(1/2) * a * b * sin(a和b的夹角) ,于是这样就只有一个总限制,那就是所有角的和=2*π。

    并且利用所有变量的偏导等于0,我们可以得到 λ = r1 * r2 *cos(r1和r2夹角) = .... ,因为最优情况肯定没有超过π的角,而cos在[0,π]上单调,所以我们二分一下λ 就可以得到最后的答案。

        当然因为不一定所有点都在凸包上出现,并且每个点出现的顺序不一定,所以我们还要枚举选ri前几大的点(贪心)和它们的顺序(全排列一下就好了)。

    #include<bits/stdc++.h>
    #define ll long long
    #define D double
    using namespace std;
    const int maxn=10;
    const D pi=acos(-1);
    D miu,l,r,thita[maxn];
    int n,R[maxn];
    
    inline D calc(){
    	D tot=0;
    	for(int i=1;i<n;i++) thita[i]=acos(miu/(R[i]*R[i+1])),tot+=thita[i];
    	thita[n]=acos(miu/(R[n]*R[1])),tot+=thita[n];
    	return tot;
    }
    
    inline void solve(){
    	D ans=0,now,le,ri;
    	
    	sort(R+1,R+n+1);
    	for(;n>=3;){
    		le=-R[1]*R[2],ri=-le;
    
    		while(1){
    			l=le,r=ri;
    			
    			while(r-l>=1e-8){
    				miu=(l+r)/2;
    				if(calc()>=2*pi) l=miu;
    				else r=miu;
    			}
    
    			if(fabs(calc()-2*pi)<=1e-6){
    			    now=0;
    			    for(int i=1;i<n;i++) now+=sin(thita[i])*(D)R[i]*(D)R[i+1];
    			    now+=sin(thita[n])*(D)R[n]*(D)R[1];
    			    ans=max(ans,now);
    		    }
    		    
    			if(!next_permutation(R+1,R+n+1)) break;
    		}
    		
    		sort(R+1,R+n+1),n--;
    		for(int i=1;i<=n;i++) R[i]=R[i+1];
    	}
    	
    	printf("%.11lf
    ",ans/2);
    }
    
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++) scanf("%d",R+i);
    	solve();
    	return 0;
    }
    

      

     

  • 相关阅读:
    [LOJ#6284.数列分块入门8] ODT(珂朵莉树)解法
    [CF Contest] Sum of Round Numbers 题解
    基础数论记录
    [CF Contest] Kana and Dragon Quest game 题解
    hexo上怎么写博客
    keepalived的部署
    python局部和全局变量
    python发送邮件
    lamp架构的部署
    rayns数据同步
  • 原文地址:https://www.cnblogs.com/JYYHH/p/8652953.html
Copyright © 2011-2022 走看看