zoukankan      html  css  js  c++  java
  • [2018.3.26集训]yja-伪模拟退火

    题目大意

    在平面上找 n 个点, 要求这 n 个点离原点的距离分别为 $r_1,r_2, cdots r_rn$. 最大化这 n 个点构成的凸包面积, 凸包上的点的顺序任意。
    注意点不一定全都要在凸包上。

    $n leq 8,r_i leq 1000$

    题解

    正解是拉格朗日乘数法。
    然而作为一只蒟蒻,当然是不会这种巧妙的操作的。

    那就乱搞吧!
    考虑使用模拟退火算法。

    初始给每个节点随机一个相对于原点的角度,并计算它们构成的凸包面积。
    设定初始温度为$pi$(角度为弧度制),并进行退火。
    每次从所有点中随机选择一个点,对其角度加上或减去温度乘上一个在$(0,1)$范围内随机的实数,计算此时的答案。
    若更优,则应用这次修改,否则不作出修改。

    随机$10$次左右即可稳定得到最优解~
    说这是伪模拟退火的原因是,模拟退火事实上还会根据温度一定概率接受一次错误的修改,而实测这样的效果并不是特别优。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef double db;
    typedef pair<db,db> pr;
    const int N=19;
    const db eps=1e-8;
    const db pi=acos(-1);
    const db mint=1e-7;
    #define x first
    #define y second
    
    int n,stk[N],rr[N];
    db r[N];
    db ang[N],ans=0.0;
    pr p[N];
    
    inline bool cmp(pr a,pr b)
    {
    	if(abs(a.x-b.x)<eps)
    		return a.y<b.y;
    	return a.x<b.x;
    }
    
    pr operator - (pr a,pr b)
    {
    	return pr(a.x-b.x,a.y-b.y);
    }
    
    inline bool cmp2(pr a,pr b)
    {
    	return atan2(a.y-p[1].y,a.x-p[1].x)<atan2(b.y-p[1].y,b.x-p[1].x);
    }
    
    inline db randf()
    {
    	return (db)rand()/(db)RAND_MAX;
    }
    
    inline db cross(pr a,pr b)
    {
    	return a.x*b.y-a.y*b.x;
    }
    
    inline db hull()
    {
    	for(int i=1;i<=n;i++)
    		p[i]=pr(cos(ang[i])*r[i],sin(ang[i])*r[i]);
    	sort(p+1,p+n+1,cmp);
    	sort(p+2,p+n+1,cmp2);
    
    	int top;
    	stk[top=1]=1;
    	for(int i=2;i<=n;i++)
    	{
    		while(top>=2 && cross(p[i]-p[stk[top-1]],p[stk[top]]-p[stk[top-1]])>eps)
    			top--;
    		stk[++top]=i;
    	}
    
    
    	db ret=0;
    	for(int i=1;i<top;i++)
    		ret+=cross(p[stk[i]],p[stk[i+1]]);
    	ret+=cross(p[stk[top]],p[stk[1]]);
    	return fabs(ret/2.0);
    }
    
    inline void work()
    {
    	for(int i=1;i<=n;i++)
    		ang[i]=randf()*pi*2.0;
    
    	db t=pi,cans=hull();
    	while(t>mint)
    	{
    		//for(int i=1;i<=1;i++)
    		{
    			int choose=rand()%n+1;
    			db inc=t*(randf()-0.5);
    			ang[choose]+=inc;
    			db tans=hull();
    			if(tans>cans)cans=tans;
    			else ang[choose]-=inc;
    		}
    		t*=0.994;
    	}
    
    	ans=max(ans,cans);
    }
    
    inline int spj()
    {
    	for(int i=1;i<=n;i++)
    		ang[i]=((db)(i-1)/(db)n)*pi*2.0;
    	printf("%.6f
    ",hull());
    	return 0;
    }
    
    int main()
    {
    	freopen("yja.in","r",stdin);
    	freopen("yja.out","w",stdout);
    
    	srand(time(0));
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%d",&rr[i]);
    		r[i]=(db)rr[i];
    	}
    
    	for(int i=2;i<=n;i++)
    		if(r[i]!=r[i-1])
    			goto hell;
    	return spj();
    
    	hell:;
    	int T=200;
    	while(T--)
    		work();
    	printf("%.8f
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    PAT:1069. The Black Hole of Numbers (20) AC
    PAT:1008. Elevator (20) AC
    PAT:1052. Linked List Sorting (25) 部分错误
    PAT:1032. Sharing (25) AC
    PAT:1059. Prime Factors (25) AC
    素数表(筛选法)
    PAT:1048. Find Coins (25)(双指针法) AC
    PAT:1048. Find Coins (25)(二分查找) AC
    iOS 9.0 设置状态栏颜色 和隐藏
    UIPageViewController用法
  • 原文地址:https://www.cnblogs.com/zltttt/p/8654946.html
Copyright © 2011-2022 走看看