模拟退火——模板

#include <cstdio>

#include <cmath>

#include <algorithm>

const double lim=0.999999;

const double eps=1e-2;

const double pi=3.141592653589793;

double tmp,maxx,minx,maxy,miny,lx,ly,dif;

int n,ns,nc;double ans;

using namespace std;

struct point

{

    double x,y;

} t[105];

struct seed

{

    double x,y,f;

}s[105],a,p;

inline double dis(double x1,double y1,double x2,double y2)

{

    return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));

}

inline double ran()

{

    return (((double)(rand()%1000+1))/1000.0);

}

void seed()

{

    for (int i=0;i<ns;i++)

    {

        s[i].x=minx+ran()*lx;

        s[i].y=miny+ran()*ly;

        s[i].f=0;

        for (int j=0;j<n;j++)

        s[i].f+=dis(s[i].x,s[i].y,t[j].x,t[j].y);

    }

}

void find()

{

    for (int i=0; i<ns; i++)

    {

        p=s[i];

        for (int j=0; j<nc; j++)

        {

            double ang=ran()*2*pi;

            a.x=p.x+tmp*cos(ang);

            a.y=p.y+tmp*sin(ang);

            if (a.x<minx||a.x>maxx||a.y<miny||a.y>maxy)

                continue;

            a.f=0;

            for (int k=0; k<n; k++)

                a.f=a.f+dis(a.x,a.y,t[k].x,t[k].y);

            dif=a.f-s[i].f;//这个是求最小,最大的话改成dif=s[i].f-a.f;

            if (dif<0.0) s[i]=a;//较优解

            else//接受较差解

            {

                dif=exp(-dif/tmp);

                if (dif>lim) s[i]=a;

            }

        }

    }

}

int main()

{

    int i;

    scanf("%d",&n);

    minx=miny=1e9;

    maxx=maxy=0;

    for(i=0;i<n;i++)

    {

        scanf("%lf%lf",&t[i].x,&t[i].y);

        minx=min(minx,t[i].x);maxx=max(maxx,t[i].x);//圈定搜索范围

        miny=min(miny,t[i].y);maxy=max(maxy,t[i].y);

    }

    lx=maxx-minx;//搜索区间长度

    ly=maxy-miny;

    tmp=max(lx,ly)/sqrt(1.0*n);

    ns=5,nc=100;

    seed();

    while (tmp>eps)

    {

        find();

        tmp=tmp*0.90;

    }

    int k=0;

    for (i=1;i<ns;i++)

    if (s[k].f>s[i].f) k=i;

    printf("%.0lf\n",s[k].f);

    return 0;

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值