首页 > 其他分享 >模拟退火

模拟退火

时间:2022-11-14 18:24:58浏览次数:41  
标签:rand int double re 模拟退火 delta calc

模拟退火(Simulate Anneal)是一种通用概率演算法,在大的搜索空间内寻找最优解,若新的状态优于当前状态,则将新的状态作为最优解,否则以一定概率接受新的状态。

模拟退火有三个因数,初始温度T0,降温系数d,终止温度Tk,通常不直接取当前解为最优解,而是维护退火过程中遇到的所有解的最优值。

inline void SimulateAnneal(){
    double t=3000;/*初始温度*/
    while(t>1e-15){/*尚未达到终止温度,可以用时间代替*/
        double nx=ansx+(rand()*2-RAND_MAX)*t,ny=ansy+(rand()*2-RAND_MAX)*t/*下一个点的坐标*/,re=calc(nx,ny)/*下一个点的答案*/,delta=re-ans;/*两点答案的差值*/
        if(delta<0){/*下一个点比当前点更优*/
            ansx=nx;
            ansy=ny;
            ans=re;
        }
        else if(exp(-delta/t)*RAND_MAX>rand()){/*以多项式概率接受下一个点的坐标*/
            ansx=nx;
            ansy=ny;
        }
        t*=0.97;/*逐步降温*/
    }
}

求n个点的带权类费马点。首先选定一个答案点并计算,之后挑选根据温度跳出一段距离,比较那个点的答案并决定是更新答案还是以一定概率接受坐标。

inline double calc(double a,double b){
    double re=0;
    for(int i=1;i<=n;i++){
        double dx=x[i]-a,dy=y[i]-b;
        re+=sqrt(dx*dx+dy*dy)*w[i];
    }
    return re;
}
inline void SimulateAnneal(){
    double t=3000;
    while(t>1e-15){
        double nx=ansx+(rand()*2-RAND_MAX)*t,ny=ansy+(rand()*2-RAND_MAX)*t,re=calc(nx,ny),delta=re-ans;
        if(delta<0){
            ansx=nx;
            ansy=ny;
            ans=re;
        }
        else if(exp(-delta/t)*RAND_MAX>rand()){
            ansx=nx;
            ansy=ny;
        }
        t*=0.97;
    }
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d%d%d",x+i,y+i,w+i),ansx+=x[i],ansy+=y[i];
    ansx/=n;
    ansy/=n;
    ans=calc(ansx,ansy);
    for(int i=1;i<=3;i++)SimulateAnneal();
    printf("%.3lf %.3lf\n",ansx,ansy);
    return 0;
}

每头牛有三个朋友,求一个排列使得每对朋友之间的距离和最小。首先列出一个排列并计算答案,每次降温时选出两头牛并交换它们的位置,注意要去重。

inline int calc(){
    int re=0;
    for(int i=1;i<=n;i++)for(int j=1;j<=3;j++)re+=abs(pos[i]-pos[f[i][j]]);
    return re;
}
inline void SimulateAnneal(){
    double t=3000;
    while(t>1e-15){
        int x=rand()%n+1,y=rand()%n+1;
        while(x==y)x=rand()%n+1,y=rand()%n+1;
        swap(pos[x],pos[y]);
        int re=calc(),delta=re-ans;
        if(delta<0)ans=re;
        else if(exp(-delta/t)*RAND_MAX<rand())swap(pos[x],pos[y]);
        t*=0.97;
    }
}

将n个数分为m组,计算每组的和,求这m个数的最小方差。对于给定序列,为了让方差最小,需要在加入数时加入当前和最小的一组,降温时随机交换两个数。

inline double calc(){
    double re=0,tmp[N];
    memset(tmp,0,sizeof(tmp));
    for(int i=1;i<=n;i++){
        int p=1;
        for(int j=1;j<=m;j++)if(tmp[j]<tmp[p])p=j;
        tmp[p]+=be[i];
    }
    for(int i=1;i<=m;i++)re+=(tmp[i]-ave)*(tmp[i]-ave);
    return sqrt(1.0*re/m);
}
inline void SimulateAnneal(){
    double t=10000;
    for(int i=1;i<=n;i++)be[i]=bl[i];
    while(t>1e-15){
        int x=rand()%n+1,y=rand()%n+1;
        while(x==y)x=rand()%n+1,y=rand()%n+1;
        swap(be[x],be[y]);
        double re=calc(),delta=re-ans;
        if(delta<0){
            ans=re;
            for(int i=1;i<=n;i++)bl[i]=be[i];
        }
        else if(exp(-delta/t)<rand())swap(be[x],be[y]);
        t*=0.97;
    }
}
    for(int i=1;i<=n;i++)scanf("%d",a+i),be[i]=bl[i]=a[i],ave+=a[i];
    ave/=m;

给出n+1个点,求一个n维球的球心坐标。初始答案点为所有点坐标和的平均值,之后计算每个维度和其他点的距离并求平均值,根据平均值计算差值,结合温度进行爬山。

inline double dist(const node&a,const node&b){
    double re=0;
    for(int i=1;i<=n;i++)re+=(a.a[i]-b.a[i])*(a.a[i]-b.a[i]);
    return sqrt(re);
}
inline void SimulateAnneal(){
    double t=10000;
    while(t>0.0001){
        double ave=0;
        for(int i=1;i<=n+1;i++)dis[i]=dist(ans,p[i]),ave+=dis[i];
        ave/=n+1;
        for(int i=1;i<=n;i++)delta.a[i]=0;
        for(int i=1;i<=n+1;i++)for(int j=1;j<=n;j++)delta.a[j]+=(dis[i]-ave)*(p[i].a[j]-ans.a[j])/ave;
        for(int i=1;i<=n;i++)ans.a[i]+=delta.a[i]*t;
        t*=0.99999;
    }
}
    for(int i=1;i<=n+1;i++)for(int j=1;j<=n;j++)scanf("%lf",(p+i)->a+j),ans.a[j]+=p[i].a[j]/(n+1);

n个城市m个堡垒,可以使k个城市成为堡垒,dis(x)表示距离城市x到最近的堡垒的距离,求max(dis(i))的最小值。每次降温时暴力求最短路,随机已选的一个点和可选但是未选的点进行交换,注意当可以全部成为堡垒时要特判。

inline void spfa(){
    queue<int>q;
    memset(dis,0x3f,sizeof(dis));
    memset(in,0,sizeof(in));
    for(int i=1;i<=m;i++)dis[pos[i]]=0,q.push(pos[i]);
    for(int i=1;i<=k;i++)dis[can[i]]=0,q.push(can[i]);
    while(!q.empty()){
        int x=q.front();
        q.pop();
        in[x]=false;
        for(int i=h[x];i;i=e[i].next){
            int y=e[i].to;
            if(dis[y]>dis[x]+e[i].w){
                dis[y]=dis[x]+e[i].w;
                if(in[y]==false){
                    in[y]=true;
                    q.push(y);
                }
            }
        }
    }
}
inline int calc(){
    spfa();
    int re=0;
    for(int i=1;i<=n;i++)re=max(re,dis[i]);
    return re;
}
inline void SimulateAnneal(){
    double t=3000;
    while(t>1e-15){
        int x=rand()%k+1,y=rand()%(can[0]-k)+1;
        swap(can[x],can[k+y]);
        int re=calc(),delta=re-ans;
        if(delta<0)ans=re;
        else if(exp(-delta/t)*RAND_MAX<=rand())swap(can[x],can[k+y]);
        t*=0.997;
    }
}
    }
    for(int i=1;i<=m;i++)cin>>pos[i],in[++pos[i]]=true;
    for(int i=1;i<=n;i++)if(in[i]==false)can[++can[0]]=i;

将一个序列分成两组且数量插值不超过1,求两组和的差值的最小值。排序后进行分组,随即交换两组中的数,注意特判只有一组的情况。

inline int calc(){
    int re=0;
    for(int i=1;i<=b[0];i++)re+=b[i];
    for(int i=1;i<=c[0];i++)re-=c[i];
    return abs(re);
}
inline void SimulateAnneal(){
    double t=3000;
    while(t>1e-15){
        int x=rand()%b[0]+1,y=rand()%c[0]+1;
        swap(b[x],c[y]);
        int re=calc(),delta=re-ans;
        if(delta<0)ans=re;
        else if(exp(-delta/t)*RAND_MAX<=rand())swap(b[x],c[y]);
        t*=0.999;
    }
}
        sort(a+1,a+1+n);
        for(int i=1;i<=n;i++){
            if(i&1)b[++b[0]]=a[i];
            else c[++c[0]]=a[i];
        }
        ans=calc();
        if(b[0]==0||c[0]==0){
            cout<<ans<<'\n';
            continue;
        }

标签:rand,int,double,re,模拟退火,delta,calc
From: https://www.cnblogs.com/safeng/p/16889899.html

相关文章

  • 基于粒子群优化和模拟退火算法增强传统聚类研究(Matlab代码实现)
    ......
  • 模拟退火
    模拟退火很多时候我们会被要求求一些函数的最值问题,但是又因为值域很大,是连续的乃至无穷的,那么搜索是搜不出来的,对于这种问题,一般来说爬山算法是很可以的,比如下边的图......
  • 模拟退火学习笔记
    1.简介模拟退火算法来源于固体退火原理,是一种基于概率的算法,将固体加温至充分高,再让其徐徐冷却,加温时,固体内部粒子随温升变为无序状,内能增大,而徐徐冷却时粒子渐趋有序,在......
  • 模拟退火学习笔记
    虽然说考前不应该碰这些随机化算法,容易影响思考,但是还是写一写吧,对于一些问题还是很好用的。概念什么是模拟退火。一句话解释,我们从一个旧状态随机出一个新状态,要从旧状......
  • 分治理 + 模拟退火(因为博客归档有问题,这两个就放一起了,以后有机会搬一下)
    分治本篇重点讲三个东西,线段树分治,点分治,以及CDQ分治。TOP1线段树分治这个算法主要是针对于一些对在线算法很不友好的题,其模型大概是维护一张图,其中的边在某个固定......
  • 学习常用模型及算法1.模拟退火算法
    title:学习常用模型及算法1.模拟退火算法excerpt:学习数学建模常用模型及算法tags:[数学建模,matlab]categories:[学习,数学建模]index_img:https://picture-......
  • 爬山算法&&模拟退火
    constdoubledown=0.996;//降温系数constdoubleeps=1e-15;//终止温度doubleansx,ansy,answ,T;structpoint{intx,y,w;}a[Z];inlinedoubledis(doub......
  • 模拟退火(SA)算法求解容量受限的车辆路径(CVRP)问题MATLAB代码
    SA求解CVRP问题的目标函数是车辆行驶总距离最小,输入数据是solomon算例中的rc208,因为求解的是CVRP问题,所以将rc208中的后三列全部删除,剩余4列,每一列含义如下:[序号X坐标Y坐......
  • 模拟退火算法通俗讲解
    编辑:连吃十三碗校正:随心目录1. 模拟退火算法基本概念2. 模拟退火算法基本流程3. 遗传模拟退火算法matlab代码1.模拟退火算法基本概念自然凝结的、不受外界干扰而形成的......
  • 【Coel.学习笔记】随机化算法:模拟退火与爬山法
    简介模拟退火(\(\text{SimulateAnneal}\))和爬山法是随机化算法,二者的原理都在于通过随机生成答案并检查,把答案逐步缩小在一个可行的区间,尽可能地靠近正确答案。在考场......