模拟退火算法 POJ 2420

【前言】先说一说什么是模拟退火,感觉很多地方都讲得挺神秘的,其实非常简单。

【模拟退火算法】转自点击打开链接

1. 模拟退火算法认识

 

   爬山算法也是一个用来求解最优化问题的算法,每次都向着当前上升最快的方向往上爬,但是初始化不同可能

   会得到不同的局部最优值,模拟退火算法就可能跳出这种局部最优解的限制。模拟退火算法是模拟热力学系统

   中的退火过程。在退火过程中是将目标函数作为能量函数。大致过程如下

 

   初始高温 => 温度缓慢下降=> 终止在低温 (这时能量函数达到最小,目标函数最小)

 

   在热力学中的退火过程大致是变温物体缓慢降温而达到分子之间能量最低的状态。设热力学系统S中有有限个且

   离散的n个状态,状态的能量为,在温度下,经过一段时间达到热平衡,这时处于状态的概率为

 

                   

 

   模拟退火算法也是贪心算法,但是在其过程中引入了随机因素,以一定的概率接受一个比当前解要差的解,并且

   这个概率随着时间的推移而逐渐降低。

2. 模拟退火算法描述

 

   若,即移动后得到更优的解,那么总是接受改移动。

   若,即移动后得到更差的解,则以一定的概率接受该移动,并且这个概率随时间推移

   逐渐降低。这个概率表示为

 

   

 

   由于是退火过程,所以dE < 0,这个公式说明了温度越高出现一次能量差为dE的降温概率就越大,温度越低,

   出现降温的概率就越小,由于dE总是小于0,所以P(dE)取值在0到1之间。伪码如下


【例题 POJ 2420】点击打开链接

【题意】给n个点,找出一个点,使这个点到其他所有点的距离之和最小,也就是求费马点。

【PS】讲道理,并不是非常信任这种做法QAQ。

【AC代码】

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define N     1005
#define INF   0x3fffffff
#define eps   1e-8 //搜索条件阀值
#define delta 0.98 //温度下降速度
#define T     100  //初始温度
using namespace std;
int dir[4][2]={{0,1},{0,-1},{-1,0},{1,0}};
struct point{
    double x,y;
    point(){}
    point(double x,double y):x(x),y(y){}
}P[N];
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 getSum(point p[],int n,point t)
{
    double sum=0;
    while(n--) sum+=dis(p[n],t);
    return sum;
}
//模拟退火
double solve(point p[],int n)
{
    point z;
    point  s   = p[0]; //随机初始化一个点开始搜索
    double t   = T;    //初始化温度
    double ans = INF;  //初始答案
    while(t>eps)
    {
        bool fuck = 1;
        while(fuck)
        {
            fuck = 0;
            for(int i=0; i<4; i++)
            {
                z.x = s.x+dir[i][0]*t;
                z.y = s.y+dir[i][1]*t;
                double tmp = getSum(p,n,z);
                if(ans>tmp)
                {
                    ans = tmp;
                    s   = z;
                    fuck= 1;
                }
            }
        }
        t*=delta;
    }
    return ans;
}
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=0; i<n; i++)
        {
            scanf("%lf%lf",&P[i].x,&P[i].y);
        }
        printf("%.0f\n",solve(P,n));
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值