cf2c(模拟退火 步长控制
https://www.luogu.org/problem/CF2C
题意:在平面上有三个没有公共部分的圆,求平面上一点使得到三个圆的切线的夹角相等。(若没答案满足条件,则不打印
思路:可用模拟退火算法来枚举答案点,可过,然而应该不是正解。先设一个最优解和初始步长,然后以当前步长不断搜索最优解更新答案,若答案不能更新,则步长减半再搜索,直到精度达到要求结束算法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | #include<cstdio> #include<cmath> const double EPS=1E-5; //控制精度 struct Point { double x,y; double r; }P[3]; double Get( double x, double y, const Point b) { //求两点之间的距离 return sqrt ((x-b.x)*(x-b.x)+(y-b.y)*(y-b.y)); } double Check( double x, double y) { //估价函数 double t[3],delta[3],ret=0.0; //t为当前视角,delta表示误差值 for ( int i=0;i<3;++i) t[i]=Get(x,y,P[i])/P[i].r; for ( int i=0;i<3;++i) { delta[i]=t[i]-t[(i+1)%3]; ret+=delta[i]*delta[i]; } return ret; //返回误差的平方和 } int main() { bool mark; double x=0.0,y=0.0; for ( int i=0;i<3;++i) { scanf ( "%lf%lf%lf" ,&P[i].x,&P[i].y,&P[i].r); x+=P[i].x/3; y+=P[i].y/3; //设置近似最优解为三个圆圆心构成的三角形重心 } for ( double t=1.0,delta;t>EPS;) { //初始步长为1 mark=0; //搜索标记 delta=Check(x,y); if (Check(x+t,y)<delta) { //搜索更优解 x+=t; mark=1; } else if (Check(x-t,y)<delta) { x-=t; mark=1; } else if (Check(x,y+t)<delta) { y+=t; mark=1; } else if (Check(x,y-t)<delta) { y-=t; mark=1; } if (!mark) //搜索不到调整步长 t/=2; } if ( fabs (Check(x,y))<EPS) //检查 printf ( "%.5lf %.5lf" ,x,y); return 0; } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步