首页 > 其他分享 >学习笔记—— % 你 退 货

学习笔记—— % 你 退 货

时间:2023-10-06 16:44:07浏览次数:45  
标签:ldb int 笔记 学习 read 模拟退火 SA define

最近对人类智慧比较感兴趣,于是学了一下这之中臭名昭著比较有名的 %你退货 模拟退火.


看不懂的定义

模拟退火算法来源于固体退火原理,

是一种基于概率的算法,将固体加温至充分高,再让其徐徐冷却,

加温时,固体内部粒子随温升变为无序状,内能增大,

而徐徐冷却时粒子渐趋有序,在每个温度都达到平衡态,最后在常温时达到基态,内能减为最小.

(别猜了就是从百度粘的)

(看个乐呵就行,没用)


个人理解

百度百科写的很反人类,但实际上这个算法非常亲民(除了调参的时候).

实际就是一种受自然现象启发发明的效率很高的随机化算法.

(像这样的算法还有很多,包括但不限于遗传算法)


大致过程

我们可以认为是在一条函数图像(一般是多峰)上有一定策略地跳来跳去.

为了便于理解,我们接下来会把这个函数图像比作一座山.

首先我们需要随便确定一个起始点(一般是选择原始数据的平均数),

然后就开始退火.

一般能模拟退火的题都会有两种东西:

一种是 '状态' ,也就是山上的点.

一种是 '结果' ,也就是当前点所在的"高度".

我们会基于当前状态点随机的跳来跳去.

对于更优的点,我们一定会接受.

而对于不更优的点呢?我们 概率接受 它.

为什么不是一定不接受?

想一个很简单的问题:高度比较高的地方就一定离山顶近吗?

显然不.

所以相比于完全贪心的爬山算法,模拟退火最大的特点就在此:

我们会以一定概率接受一个比当前状态不更优的点.

这个概率函数为

\[e^{-\Delta/T} \]


参数

模拟退火的框架大概是这样的:

const ldb down=0.996;
const ldb edge=RAND_MAX;
#define ldb long double
//请务必注意你变量的类型
//作者曾不止一次因为ldb写成int调了半天

void SA()
{
    ldb T=3000;//初始温度
    while(T>=1e-15)
    {
        int ex=x+rnd();// 随机化得到新状态
        int eans=energy(ex);//求这个新状态对应的结果

        int D=eans-ans;//新结果与原结果的差值

        if(D<0)
            x=ex,ans=eans;//新结果更优,接受
        else if(exp(-D/T)*edge>rnd())
            x=ex;//否则一定概率接受这个状态

        T*=down;//降温
    }
}

可以发现里面有很多参数,包括但不限于

\(T\)(初始温度),\(1e-15\)(终止温度),\(down\)(退火速度).

在实际的题目中,我们会不断地改变他们的值以控制运行时间或是提高正确率.

这个过程叫调参,可以认为是整个模拟退火中最麻烦的一部分.


一 些 例 题

P1337 [JSOI2004] 平衡点 / 吊打XXX

著名的模拟退火板子题.枚举的是重心的位置.

根据一些除了作者人人都会的物理知识,由重心产生的答案是最小的.

#include<bits/stdc++.h>
using namespace std;
#define il inline
#define endl '\n'
const int N=1017000;
const int edge=RAND_MAX;
#define ldb long double
#define Croll(i,l,r) for(int i=l;i<=r;++i)
#define Troll(i,l,r) for(int i=l;i>=r;--i)
//////////
const ldb down=0.996;

int n;
struct starfield
{int x,y,w;}o[N];

void SA();

ldb ansx,ansy,answ;
ldb heart(ldb,ldb);
//////////
il int read();
//////////
int main()
{
    srand(time(0));

    n=read();
    Croll(i,1,n)
    {
        o[i]={read(),read(),read()};
        ansx+=o[i].x,ansy+=o[i].y;
    }
    ansx/=n;ansy/=n;
    answ=heart(ansx,ansy);

    SA();SA();SA();SA();
    SA();SA();SA();SA();
    SA();SA();SA();SA();
    SA();SA();SA();SA();
    //矩阵加速()

    printf("%.3Lf %.3Lf",ansx,ansy);

    return 0;
}
//////////
void SA()
{
    ldb T=3000;
    while(T>1e-15)
    {
        ldb ex=ansx+(rand()*2-edge)*T;
        ldb ey=ansy+(rand()*2-edge)*T;
        // cout<<ex<<" "<<ey<<endl;
        if(ex>10000||ey>10000||ex<-10000||ey<-10000)
        {
            T*=down;
            continue;
        }
        ldb ew=heart(ex,ey);
        ldb De=ew-answ;
        if(De<0)
        {
            ansx=ex;ansy=ey;
            answ=ew;
        }
        else if(exp(-De/T)*edge>rand())
        {
            ansx=ex;ansy=ey;
        }
        T*=down;
    }
}

ldb heart(ldb x,ldb y)
{
    ldb ans=0,dx,dy;
    Croll(i,1,n)
    {
        dx=x-o[i].x;
        dy=y-o[i].y;
        ans+=sqrt(dx*dx+dy*dy)*o[i].w;
    }
    return ans;
}
//////////
il int read()
{
    int f=1,x=0;char w=getchar();
    while(w<'0'||w>'9')
    {if(w=='-')f=-1;w=getchar();}
    while(w>='0'&&w<='9')
    {x=(x<<3)+(x<<1)+(w^48);w=getchar();}
    return f*x;
}

P2210 Haywire

个人感觉这道题比较有代表性.

这道题代表了模拟退火能处理的第二类问题:
通过改变序列元素的顺序得到答案.

#include<bits/stdc++.h>
using namespace std;
#define il inline
#define endl '\n'
const int N=1017;
#define lol long long
#define ldb long double
#define Croll(i,l,r) for(int i=l;i<=r;++i)
#define Troll(i,l,r) for(int i=l;i>=r;--i)
//////////
#define fr first
#define sc second
#define PII pair <int,int>

const ldb down=0.996;
const int edge=RAND_MAX;
mt19937 rnd(19280817);
//////////
int n,tot;
PII frd[N];

int pos[N];
void SA();

int ans;
int energy();
//////////
il int read();
//////////
int main()
{
    n=read();
    Croll(i,1,n)
    {
        int f1=read(),f2=read(),f3=read();
        if(f1>i)
            frd[++tot]={i,f1};
        if(f2>i)
            frd[++tot]={i,f2};
        if(f3>i)
            frd[++tot]={i,f3};
    }
    Croll(i,1,n)
        pos[i]=i;
    ans=energy();

    SA();SA();SA();SA();
    SA();SA();SA();SA();
    SA();SA();SA();SA();
    SA();SA();SA();SA();

    cout<<ans<<endl;

    return 0;
}
//////////
void SA()
{
    ldb T=3000;
    while(T>1e-15)
    {
        int rx=rnd()%n+1,ry=rnd()%n+1;
        swap(pos[rx],pos[ry]);

        int e=energy();
        int D=e-ans;
        if(D<0)
            ans=e;
        else if(exp(-D/T)*edge<rnd())
            swap(pos[rx],pos[ry]);
			//注意:这里的意思是,1-exp(-D/T)的概率变回原状态,等价于exp(-D/T)的概率接受当前状态
        
        T*=down;
    }
}

int energy()
{
    int dis=0;
    Croll(i,1,tot)
    {
        int x=frd[i].fr,y=frd[i].sc;
        dis+=abs(pos[x]-pos[y]);
    }
    return dis;
}
//////////
il int read()
{
    int f=1,x=0;char w=getchar();
    while(w<'0'||w>'9')
    {if(w=='-')f=-1;w=getchar();}
    while(w>='0'&&w<='9')
    {x=(x<<3)+(x<<1)+(w^48);w=getchar();}
    return f*x;
}

标签:ldb,int,笔记,学习,read,模拟退火,SA,define
From: https://www.cnblogs.com/Cayde-6/p/17744703.html

相关文章

  • Redis学习之分布式全局id生成
    介绍为什么需要分布式全局ID生成器?对于订单这种数据,数据库自增的规律性太明显,会暴露一些信息(比如根据昨日和今日的订单号差值看出销量)数据量过大时,不同表的id分别自增,容易出现id冲突分布式全局ID生成应满足的特点:唯一:整个系统每个id都是唯一的递增......
  • docker笔记
    假设容器id为3a9ac4d50f7d开机时启动dockersudosystemctlstartdocker查看docker情况systemctlstatusdocker重启daemonsystemctldaemon-reload容器配置存放路径/var/lib/docker/containers/https://blog.csdn.net/sosous/article/details/122758984dockerstart容......
  • 如何选购一台适合写代码的笔记本电脑
    如何选购一台适合写代码的笔记本电脑 1.参考指标选择一台写代码的笔记本,其实是很好选择的。不像是选择游戏本,各个指标的性能必须拉满,因为写代码不吃显卡,这块预算可以直接砍掉,用集成显卡就完全可以,把这部分的钱换成别的配置,那么写代码的体验就可以起飞了。下面我讲......
  • 2023-2024-1 学号20231315《计算机基础与程序设计》第二周学习总结
    学期:2023-2024-1学号:20231315《计算机基础与程序设计》第二周学习总结作业信息这个作业属于哪个课程2023-2024-1《计算机基础与程序设计》这个作业要求在哪里2023-2024-1《计算机基础与程序设计》这个作业的目标学习计算机科学概论第1章和《C语言程序设计》第1......
  • 笔记本上搭建PXE环境
    环境准备1、Tftpd64工具下载地址:https://pjo2.github.io/tftpd64/2、HFS(简易HTTP服务器)工具下载地址:http://www.rejetto.com/hfs/3、ISO镜像文件:Linux发行版(本章实验用的是centos7.9的镜像) 1、在桌面新建一个目录文件(我这就叫PXE)\PXE\PXE\pxe-inst......
  • Redis学习之缓存雪崩、缓存击穿及封装Redis工具类
    缓存雪崩缓存雪崩是指在同一时段大量的缓存key同时失效或者Redis服务宕机,导致大量请求到达数据库,带来巨大压力。解决思路:1.不让key同时失效2.尽量不让Redis宕机具体解决方案:缓存击穿又叫热点key失效:两种解决方案:1.互斥锁:只有一个线程会负责缓存重建,其余线程拿不到锁,就......
  • 性能测试学习笔记(四)
    一、关联和断言满足如下条件的数据都是需要关联的:1.数据是由服务器端生成的;2.数据在每一次请求时都是动态变化的;3.数据在后续的请求中需要再发送出去。JMeter中常用于数据关联的组件:1、JSON提取器(提取JSON格式的响应数据)2、Xpath提取器(提取HTML格式的响应数据)3、正则表......
  • 不同宽度,厚度,重量,车间温度,冷却方式下,物料温度随时间衰减,请使用python机器学习,
    生成模拟数据、数据预处理、选择模型、划分数据集、训练模型、调整超参数、预测和评估以及绘图是一个相对复杂的流程。下面是一个示例流程,涵盖了这些步骤:importnumpyasnpimportpandasaspdimportmatplotlib.pyplotaspltfromsklearn.model_selectionimporttrain_test_......
  • 不同宽度,厚度,重量,车间温度,冷却方式下,物料温度随时间呈指数衰减,,请使用python机
    生成模拟数据、数据预处理、选择模型、划分数据集、训练模型、调整超参数、预测和评估以及绘制图表是一个完整的机器学习项目流程。下面是一个用Python完成这些步骤的基本示例。请注意,这只是一个简单的示例,实际项目中可能需要更复杂的数据和模型选择。首先,确保你已经安装了必要的Py......
  • 不同宽度,厚度,重量,车间温度下,物料温度随时间而衰减的曲线不同,请使用python机器学
    要使用Python机器学习拟合物料温度随时间衰减的曲线,你可以遵循以下步骤:收集数据:首先,你需要收集不同宽度、厚度、重量和车间温度下的物料温度随时间的数据。确保数据集包含了足够的样本,以便于训练和测试机器学习模型。数据预处理:对数据进行预处理,包括数据清洗、缺失值处理和特征工程......