poj 3285 模拟退火,


参考:http://boatswain.info/lovers/wordpress/?p=124

本题给出了三个圆形,求一点,使得该点到三个圆的视角相同。 不存在,则输出没有解决方案。

 

本题的难点是用模拟退火的时候,如何逼近最优解。也就是说,如何使得三个视角越来越接近,=> 三个视角的方差最小。

当想到了这个以后,接下来就是什么情况输出不存在了。很明显,在无穷远出必然是存在点的。排除无穷远处,则该点必然在

三个圆的里面,也就是如图所示(

  • The discs centers are not all collinear.
  • The discs are totally disjoint.
  • )题目已经暗示我们了三个圆不相交,并且几何中心不在同一直线上。
  • /*
    
    模拟退火法
    模拟退火的过程
    1 找到这些点所在的范围,用两个点框定(代码中e1,e2两个点)
    2 在这个范围内生成NUM个点(NUM自定)
    3 对于每个生成的点i,在其周围生成NUM个点,一旦有点优于i,则替换。
    4 缩小范围D,若D<精度,退出,否则执行 3
    5 遍历所有NUM个点,找到val为0的点
    */
    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    #include <cstring>
    #include <string>
    #include <algorithm>
    #include <set>
    #include<map>
    #include<ctime>
    using namespace std;
    const double eps=1e-6;
    const double inf=1e9;
    bool dy(double x,double y)  {   return x > y + eps;} // x > y   
    bool xy(double x,double y)  {   return x < y - eps;} // x < y   
    bool dyd(double x,double y) {   return x > y - eps;} // x >= y   
    bool xyd(double x,double y) {   return x < y + eps;}     // x <= y   
    bool dd(double x,double y)  {   return fabs( x - y ) < eps;}  // x == y  
    const int NUM=20;
    const int RAD=1000;
    struct point
    {
    	double x,y,val;
    	point(){}
    	point(double _x,double _y):x(_x),y(_y){}
    }p[3],May[NUM],e1,e2;
    int n;
    double X,Y;
    double dis(point a,point b)
    {
    	return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
    }
    double judge(point t)//评价函数,得到点t的评价值val
    {
    	double Sin[3],avg,sum=0.0;
    	for(int i=0;i<3;i++){ Sin[i]=p[i].val/dis(t,p[i]);sum+=Sin[i];}
    	avg=(sum)/3.0;
    	sum=0.0;
    	for(int i=0;i<3;i++) sum+=sqrt(10*(Sin[i]-avg)*(Sin[i]-avg));
    	return sum;
    }
    double Rand(){return rand()%(RAD+1)/(1.0*RAD);}//随机产生0-1的浮点数
    point Rand_point(point a,point b)//在a,b框定的四边形内随机生成点
    {
    	double xx=a.x+(b.x-a.x)*Rand();
    	double  yy=a.y+(b.y-a.y)*Rand();
    	point tmp=point(xx,yy);
    	tmp.val=judge(tmp);
    	return tmp;
    }
    void solve(double D)
    {
    	for(int i=0;i<NUM;i++)
    	May[i]=Rand_point(e1,e2);//步骤2
    	while(D>0.001)//步骤 3
    	{
    		for(int i=0;i<NUM;i++)
    		for(int j=0;j<NUM;j++)
    		{
    			point tmp=Rand_point(point(max(e1.x,May[i].x-D),max(e1.y,May[i].y-D)),point(min(e2.x,May[i].x+D),min(e2.y,May[i].y+D)));
    			if(tmp.val<May[i].val)
    			{
    				May[i]=tmp;
    			}
    		}
    		D*=0.9;
    	}
    	point ans;
    	ans.val=inf;
    	for(int i=0;i<NUM;i++)
    	if(ans.val>May[i].val)
    	ans=May[i];
    	if(ans.val<eps)
    	printf("%.2f %.2f\n",ans.x,ans.y);
    	else 
    	puts("No solution");
    }
    int main()
    {
    	srand(time(0));
    	while(1)
    	{
    	e2=point(-inf,-inf);
    	e1=point(inf,inf);
    		int num=0;
    		for(int i=0;i<3;i++)
    		{
    		scanf("%lf%lf%lf",&p[i].x,&p[i].y,&p[i].val);
    		e1.x=min(p[i].x,e1.x);
    		e1.y=min(p[i].y,e1.y);
    		e2.x=max(p[i].x,e2.x);
    		e2.y=max(p[i].y,e2.y);
    		if(dd(p[i].x,0.0)&&dd(p[i].y,0.0)&&dd(p[i].val,0.0))
    		num++;
    		}
    		if(num==3)break;
    		solve(max(e2.x-e1.x,e2.y-e1.y));
    	}
    }


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值