• 模拟退火学习


    模拟退火学习

    作业部落
    网上讲的不错的(他好像还有一些其他的东西、、、)

    引入

    对于一些题目,无法直接算出答案或者想不到正解,想到随机找答案,那么模拟退火就是一种有系统方法的随机算法

    没用的不需要了解的来源

    百度百科......
    模拟退火算法来源于固体退火原理,是一种基于概率的算法,将固体加温至充分高,再让其徐徐冷却,加温时,固体内部粒子随温升变为无序状,内能增大,而徐徐冷却时粒子渐趋有序,在每个温度都达到平衡态,最后在常温时达到基态,内能减为最小。

    几个要记下来的东西

    1. 温度:大概理解为答案的波动范围,看是否会接受不那么好的解
    2. 爬山算法:找很多个答案起点,遇到峰值就记录答案,最后找最大(小)答案

    用途

    1. 数据范围不大但爆搜显然过不了的题目
    2. 有一定的求解规律但又不完全符合规律的题目
    3. 多峰函数题或者算数几何之类的题目
    4. 题目想不出,退火总比爆0好的题目

    主要思想

    • 把当前答案看成一只退火兔,一开始很急躁(温度很高),所以答案到处乱跑(这中间会记录最优解),最后兔子慢慢冷静下来(温度逐渐降低),就找到答案
    • 利用rand来寻找答案接受劣解的波动范围(当然T也是一个决定性参数)
    • 退火找答案之后,可能会有更优答案在自己周围很近的地方,所以rand去周围看一看是否更优
    • 一开始根据自己的猜测来找一个答案“开始”点,可以降低一定时间复杂度......

    板子

    我只讲大致的思想,具体实现根据模板题及luogu的题解讲述来学习吧
    主要是懒

    first

    luogu板子题平衡点/吊打xxx
    然后,我的优美代码......

    #include<iostream>
    #include<cstdlib>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<iomanip>
    #include<algorithm>
    #include<ctime>
    #include<queue>
    #include<stack>
    #include<vector>
    #define rg register
    #define il inline
    #define lst long long
    #define ldb long double
    #define cold 0.99
    #define N 1050
    #define RD T*((rand()<<1)-RAND_MAX)//rand一个-T到T的数,随机跳多远
    #define Time() (ldb)clock()/(ldb)CLOCKS_PER_SEC
    using namespace std;
    const int Inf=1e9;
    
    int n;
    ldb ansx,ansy,ans;
    ldb etlx,etly,etl;
    struct WEI{
        ldb x,y,m;
    }ljl[N];
    
    il int read()
    {
        rg int s=0,m=0;rg char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')m=1;ch=getchar();}
        while(ch>='0'&&ch<='9')s=(s<<3)+(s<<1)+(ch^48),ch=getchar();
        return m?-s:s;
    }
    
    il ldb f(rg ldb xx,rg ldb yy)
    {
        rg ldb res=0;
        for(rg int i=1;i<=n;++i)
        {
            rg ldb dx=xx-ljl[i].x,dy=yy-ljl[i].y;
            res+=sqrt(dx*dx+dy*dy)*ljl[i].m;
        }
        return res;
    }
    
    int main()
    {
        srand(time(NULL));
        n=read();
        for(rg int i=1;i<=n;++i)
        {
            scanf("%Lf%Lf%Lf",&ljl[i].x,&ljl[i].y,&ljl[i].m);
            ansx+=ljl[i].x,ansy+=ljl[i].y;
        }
        etlx=ansx=ansx/n,etly=ansy=ansy/n;
        etl=ans=f(ansx,ansy);
        while(Time()<0.3)
        {
            rg ldb nans=etl,nx=etlx,ny=etly;
            for(rg ldb T=1000;T>=1e-16;T*=cold)
            {
                rg ldb xx=nx+RD,yy=ny+RD;//模拟退火答案的波动范围
                rg ldb res=f(xx,yy);//找答案的ans
                if(ans>res)ans=res,ansx=xx,ansy=yy;//更新答案
                if(nans>res||exp((res-nans)/T)*RAND_MAX<rand())
                    nans=res,nx=xx,ny=yy;
            }
        }
        printf("%.3Lf %.3Lf
    ",ansx,ansy);
        return 0;
    }
    

    second

    有难度,luogu均分数据

    #include<iostream>
    #include<cstdlib>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<iomanip>
    #include<algorithm>
    #include<ctime>
    #include<queue>
    #include<stack>
    #include<vector>
    #define rg register
    #define il inline
    #define lst long long
    #define ldb long double
    #define N 25
    #define M 10
    #define Time() (ldb)clock()/(ldb)CLOCKS_PER_SEC
    using namespace std;
    const int Inf=1e5;
    
    int n,m;
    ldb tot,ans=Inf;
    ldb v[N],sum[N];
    ldb dp[N][N];
    
    il int read()
    {
        rg int s=0,m=0;rg char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')m=1;ch=getchar();}
        while(ch>='0'&&ch<='9')s=(s<<3)+(s<<1)+(ch^48),ch=getchar();
        return m?-s:s;
    }
    
    il ldb PF(rg ldb x){return x*x;}
    il ldb sol()
    {
        for(rg int i=1;i<=n;++i)sum[i]=sum[i-1]+v[i];
        for(rg int i=0;i<=n;++i)
            for(rg int j=0;j<=m;++j)dp[i][j]=Inf;
        dp[0][0]=0;
        for(rg int i=1;i<=n;++i)
            for(rg int j=1;j<=m;++j)
                for(rg int k=0;k<i;++k)
                    dp[i][j]=min(dp[i][j],dp[k][j-1]+PF(sum[i]-sum[k]-tot));
        ans=min(ans,dp[n][m]);
        return dp[n][m];
    }
    
    il void SA(rg ldb T)
    {
        rg ldb nans=ans;
        for(;T>1e-3;T*=0.98)
        {
            rg int xx=1+rand()%n,yy=1+rand()%n;
            if(xx==yy)continue;
            swap(v[xx],v[yy]);
            rg ldb res=sol();
            if(res<nans||exp((res-nans)/T)*rand()-RAND_MAX<0)nans=res;
            else swap(v[xx],v[yy]);
        }
    }
    
    int main()
    {
        n=read(),m=read();
        for(rg int i=1;i<=n;++i)
            v[i]=read(),tot+=v[i];
        tot/=m,sol();
        while(Time()<0.3)
            SA(1000);
        printf("%.2Lf
    ",sqrt(ans/m));
        return 0;
    }
    
  • 相关阅读:
    个人作业3——个人总结(Alpha阶段)
    结对编程2 单元测试
    英语学习app案例分析
    结对作业1
    java四则运算生成器
    个人附加作业 201421123108 王坤彬 网络1414
    个人作业3-(Alpha阶段)
    结对编程之单元测试 201421123108 王坤彬
    英语学习案例分析APP 201421123108 王坤彬
    结对编程 王坤彬 201421123108
  • 原文地址:https://www.cnblogs.com/cjoierljl/p/9394519.html
Copyright © 2020-2023  润新知