模拟退火浅记
模拟退火
const double delta=...; //调一个适合自己的降温参数
int calc()
{
//用dp,最短路,贪心,模拟等算法求出当前解。
}
int SA()
{
int T=...; //初始温度
int T0=...; //最终温度
while(T>T0){
//对于序列,枚举两个数并进行交换,得出当前解
//对于坐标,随机生成一个点进行计算
//对于网格图,随机枚举两个格点进行交换
//...
if(当前解优于最优解) 更新最优解
else if(一定概率不接受) //还原之前的状态
T*=delta; //模拟降温过程
}
}
int main()
{
srand(time(0));srand(rand());srand(rand());
/*主程序*/
}
注意:
int posa=rand()%n+1;
int posb=rand()%n+1;
//注意需要 +1
if(de<0) ...
else if(exp(-1.0*de/t)*RAND_MAX<rand()) ... //这里是**不接受**新解的情况
// exp(-1.0*de/t)*RAND_MAX>rand() 则是**接受**新解的情况
// t 越大,exp(-1.0*de/t)*RAND_MAX 越大,接受新解的概率越大
//注意要保证 exp 函数中的数为负
-
答案要先初始化,就是一开始的时候要 Calc 求一下答案
-
利用卡时技巧多跑退火
while((double)clock()/CLOCKS_PER_SEC<0.9)
SA();
最好不要开到 0.9
多组数据最好不要卡时,或者说平均分配一下每组数据的时限
利用卡时技巧时在本地运行需要用 freopen 来进行数据读入,因为直接在程序上输入的话输入的时间也会算进程序运行时间,导致无法跑模拟退火函数,利用 luogu ide 也可以。
-
模拟退火 WA 了可能是因为码错了,也可能是因为自己的参数没调好,WA了太多次的话建议重构
-
对于一些题目的数据很小的话,rand 有的时候的随机性不强,建议是
-> rand()*rand()
或 ((rand()&32767)<<15)|(rand()&32767)
因为 rand() 最大只有 2^15
或用 mt19937
- 当函数的峰很多时,模拟退火难以跑出最优解,那么可以将值域分成若干段,对于每一段再跑一边模拟退火。
其中段数不一定是要 sqrt n 段,需要根据函数峰值的周期大概估算一下段数。
- 一般温度 t 可设为 3000 , Down 可设为 0.97 , t_k 可设为 1e-10 , rand() 的种子自选,跑退火的次数需视具体题目而定。
这个主要可以看个人喜好(
- 如果是小数据,rand 下标交换数组值的时候,两个下标可能会 rand 到同一个值,这时不妨继续退火下去,因为数据小、rand 随机性比较差,如果直接 continue 则可能难以使温度下降,进而导致 TLE
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通