模拟退火入门——POJ 2420

「爱情、让人受尽委屈。」 2022-05-08 13:14 301阅读 0赞

题目链接:
POJ 2420

题目大意:
给出平面上N(<=100)个点,你需要找到一个这样的点,使得这个点到N个点的距离之和尽可能小。输出这个最小的距离和(四舍五入到最近的整数)

解题思路:
如果下午不是马原课无聊,学习了一下模拟退火的思想,大概看到这题也没太多想法,不过是真的神奇啊,先放上我觉得讲得很简单的模拟退火算法的一个讲解
大白话解析模拟退火算法

看完之后,总结就是,每次把下一个状态和当前状态对目标答案进行比较,如果比当前更优或者其exp(dE/T) 在(0,1)之间,则进行退火(即T乘以某个不大于1的正数),然后不断更新下一状态,直到T小于某个T_min(一般比较小,1e-3这样吧,具体看题目,或者经验也是很重要感觉2333,包括上面对T退火的那个数也有讲究,多练吧!)
最后就有很可能得到最优解了!!!

回到本题,初始状态的话,当然是所有点的平均位置的那个点,目标答案是和其他点的距离和,这里我们每次随机生成一个角度,然后用当前点坐标和T得到下一个状态的坐标。计算各到其他点的距离和,记录最小值,然后不断退火,就可以很大概率得到最优解

AC代码:

  1. #include <iostream>
  2. #include <algorithm>
  3. #include <cstdio>
  4. #include <cmath>
  5. #include <cstring>
  6. #define INF 1e17
  7. #define EPS 1e-3
  8. #define PI acos(-1)
  9. #define FIRE(x) (x *= 0.99)
  10. using namespace std;
  11. struct Point{
  12. double x,y;
  13. Point(){}
  14. Point(double _x, double _y):x(_x),y(_y){}
  15. void operator +=(const Point t){
  16. x += t.x; y += t.y;
  17. }
  18. };
  19. Point p[150],now;
  20. int n;
  21. double ans;
  22. double getDist(double x,double y){
  23. double ret = 0;
  24. for(int i=0; i<n; ++i){
  25. ret += sqrt((p[i].x-x)*(p[i].x-x)*1.0 + (p[i].y-y)*(p[i].y-y)*1.0);
  26. }
  27. if(ret < ans) ans = ret;
  28. return ret;
  29. }
  30. double Rand(){
  31. return (rand()%1000+1)/1000.0;
  32. }
  33. void solve(){
  34. double T = 100000.0,alpha,sub;
  35. while(T > EPS){
  36. alpha = 2.0*PI*Rand();
  37. Point tmp(now.x + T*cos(alpha), now.y + T*sin(alpha));
  38. sub = getDist(now.x,now.y) - getDist(tmp.x,tmp.y);
  39. if(sub >=0 || exp(sub/T) >= Rand()) now = tmp;
  40. FIRE(T);
  41. }
  42. }
  43. int main(){
  44. srand(100233);
  45. scanf("%d",&n);
  46. for(int i=0; i<n; ++i){
  47. scanf("%lf%lf",&p[i].x,&p[i].y);
  48. now += p[i];
  49. }
  50. ans = 0x3f3f3f3f;
  51. now.x /=n; now.y /=n;
  52. solve();
  53. printf("%.f\n",ans);
  54. return 0;
  55. }

发表评论

表情:
评论列表 (有 0 条评论,301人围观)

还没有评论,来说两句吧...

相关阅读

    相关 模拟退火

    Summary 退火总结.退火其实不难...难的是怎么调参. 贡献两页提交才只有\\(55pts\\)的经历真是惨不忍睹.这就是调参的艰难. 主要就是这么几个参数

    相关 模拟退火算法(代码)

    在实际日常中,人们会经常遇到如下问题:在某个给定的定义域![X][]内,求函数![f(x)][f_x]对应的最优值。此处以最小值问题举例(最大值问题可以等价转化成最小值问题),

    相关 模拟退火入门题*3

    CTS2019Day2T1出了道可以乱搞的的计算几何,我辛辛苦苦写了280多行,结果就给了我10分,这不气炸了。 据我分析,可能是因为我没有学过模拟退火,乱搞是真的乱搞,儿