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

模拟退火

时间:2023-07-16 14:22:34浏览次数:39  
标签:int double rd 模拟退火 ans now

引入

模拟退火是一种随机化算法,当一个问题方案数量极大且非单峰时,我们常使用模拟退火

过程

先引入几个参数:当前最优解 \(E_0\) ,新解 \(E\) ,解变动量 \(\Delta E\) (即 \(E\) 与 \(E_0\) 的差),上一个被接受的解 \(E_1\) ,初温 \(T_0\) ,末温 \(T_k\) ,当前温度 \(T\) ,温度变动量 \(\Delta\)

从 \(T_0\) 开始,每次乘上 \(\Delta\) 得到 \(T\) ,如果 \(T < T_k\) 则终止降温

在降温的同时,我们在 \(E_1\) 的基础上扰动产生新解 \(E\) (扰动大小随温度降低而变小,因为温度高时解的变化量很大,此时的任务是在全局范围中找到最优解的大致位置;随着温度的降低,解逐渐稳定,此时的任务就是确定最优解的准确位置)

每次得出新解之后,我们用Metropolis准则来接受它,假设我们碰到一个更优解,那我们就接受当前解,否则我们也要以一定概率接受更劣解,否则就会局限在一个局部峰值,而这个概率是 \(\exp(-\dfrac{\Delta}{T})\)

一般来说,对于 \(\Delta E\) ,如果其较大,即我们遇到一个差得很的解,那我们接受的概率就比较小,否则接受的概率更大。对于 \(T\) ,随着时间增加,\(T\) 变得越来越小,故我们只会接受 \(\Delta E\) 较小的解

\(T_0\) 一般设置在 \(1 \times 10^3 \sim 5 \times 10^3\) ,\(\Delta\) 则是一个略小于 \(1\) 的常数, \(T_k\) 一般设置在 \(10^{-8} \sim 10^{-15}\)

分块模拟退火

函数的峰很密集时模拟退火是不好用的,这时可以用分块模拟退火的做法,将其分为几块,然后对每块跑一遍模拟退火,最后再合并答案

随机化技巧

mt19937 gen(chrono::system_clock::now().time_since_epoch().count());


inline double rd(double l, double r) {
	return uniform_real_distribution<>(l,r)(gen);
}

应用

A Star not a Tree?

求最小值

#include <bits/stdc++.h>
using namespace std;
const double delta = 0.997, T0 = 3e3, Tk = 1e-17;
const int N = 5e3 + 7;

struct Point {
	double x, y;
} a[N];

mt19937 gen(chrono::system_clock::now().time_since_epoch().count());
double ax, ay, nx, ny, ans;
int n;

inline double rd(double l, double r) {
	return uniform_real_distribution<>(l, r)(gen);
}

inline double calc(double x, double y) {
	double res = 0;
	
	for (int i = 1; i <= n; ++i)
		res += sqrt((x - a[i].x) * (x - a[i].x) + (y - a[i].y) * (y - a[i].y));
	
	return res;
}

inline void SimulateAnneal() {
	for (double x = nx, y = ny, T = T0; T > Tk; T *= delta) {
		double _x = x + T * rd(-1000, 1000);
		double _y = y + T * rd(-1000, 1000);
		double now = calc(_x, _y), deltaE = now - ans;
		
		if (ans > now) {
			nx = _x, ny = _y;
			x = _x, y = _y;
			ans = now;
		} else if (exp(-deltaE / T) > rd(0, 1))
			x = _x, y = _y;
	}
}

signed main() {
	srand(time(NULL));
	int T;
	scanf("%d", &T);
	
	for (; T; --T) {
		scanf("%d", &n);
		ax = ay = 0, ans = 1e18;
		
		for (int i = 1; i <= n; ++i) {
			scanf("%lf%lf", &a[i].x, &a[i].y);
			ax += a[i].x, ay += a[i].y;
		}
		
		nx = ax / n, ny = ay / n;
		SimulateAnneal();
		SimulateAnneal();
		SimulateAnneal();
		SimulateAnneal();
		SimulateAnneal();
		printf("%.0lf\n", round(ans));
		
		if (T > 1)
			putchar('\n');
	}
	
	return 0;
}

P5544 [JSOI2016] 炸弹攻击1

求最大值

#include <bits/stdc++.h>
using namespace std;
const double delta = 0.9997, T0 = 2.5e3, Tk = 1e-8;
const double eps = 1e-8, MaxTime = 0.8;
const int N = 1e3 + 7;

struct Building {
	double x, y, r;
} a[N];

struct Enemy {
	double x, y;
} b[N];

mt19937 gen(chrono::system_clock::now().time_since_epoch().count());
double R, nx, ny;
int n, m, ans;

inline double rd(double l, double r) {
	return uniform_real_distribution<>(l,r)(gen);
}

inline double dist(double x, double y, double xx, double yy) {
	return sqrt((x - xx) * (x - xx) + (y - yy) * (y - yy));
}

inline int calc(int x, int y) {
	double maxlen = R;
	
	for (int i = 1; i <= n; ++i)
		maxlen = min(maxlen, dist(x, y, a[i].x, a[i].y) - a[i].r);
	
	if (maxlen < 0)
		return 0;
	
	int res = 0;
	
	for (int i = 1; i <= m; ++i)
		if (dist(x, y, b[i].x, b[i].y) < maxlen + eps)
			++res;
	
	return res;
}

inline void SimulateAnneal() {
	for (double x = nx, y = ny, T = T0; T > Tk; T *= delta) {
		double _x = x + T * rd(-10, 10);
		double _y = y + T * rd(-10, 10);
		double now = calc(_x, _y), deltaE = now - ans;
		
		if (ans < now)
			nx = x = _x, ny = y = _y, ans = now;
		else if (exp(-deltaE / T) < rd(0, 1))
			x = _x, y = _y;
	}
}

signed main() {
	scanf("%d%d%lf", &n, &m, &R);
	
	for (int i = 1; i <= n; ++i)
		scanf("%lf%lf%lf", &a[i].x, &a[i].y, &a[i].r);
	
	double bx = 0, by = 0;
	
	for (int i = 1; i <= m; ++i) {
		scanf("%lf%lf", &b[i].x, &b[i].y);
		bx += b[i].x, by += b[i].y;
	}
	
	nx = bx / m, ny = by / m;
	ans = calc(nx, ny);
	
	while ((double)clock() / CLOCKS_PER_SEC < MaxTime)
		SimulateAnneal();
		
	printf("%d", ans);
	return 0;
}

标签:int,double,rd,模拟退火,ans,now
From: https://www.cnblogs.com/wshcl/p/17557823.html

相关文章

  • 优化算法——模拟退火算法
    模拟退火算法原理爬山法是一种贪婪的方法,对于一个优化问题,其大致图像(图像地址)如下图所示:其目标是要找到函数的最大值,若初始化时,初始点的位置在处,则会寻找到附近的局部最大值点处,由于点出是一个局部最大值点,故对于爬山法来讲,该算法无法跳出局部最大值点。若初始点选择在处,根据爬......
  • 基于模拟退火优化算法的三维装箱优化matlab仿真,优化重量利用率和空间利用率
    1.算法仿真效果matlab2022a仿真结果如下:2.算法涉及理论知识概要模拟退火算法来源于固体退火原理,是一种基于概率的算法,将固体加温至充分高,再让其徐徐冷却,加温时,固体内部粒子随温升变为无序状,内能增大,而徐徐冷却时粒子渐趋有序,在每个温度都达到平衡态,最后在常温时达到基态,内能减......
  • 基于模拟退火优化算法的三维装箱优化matlab仿真,优化重量利用率和空间利用率
    1.算法仿真效果matlab2022a仿真结果如下:     2.算法涉及理论知识概要      模拟退火算法来源于固体退火原理,是一种基于概率的算法,将固体加温至充分高,再让其徐徐冷却,加温时,固体内部粒子随温升变为无序状,内能增大,而徐徐冷却时粒子渐趋有序,在每个温度都达到平......
  • 模拟退火
    模拟退火模拟退火是一种随机化算法,当一个问题的方案数极大(甚至是无穷的)而且不是一个单峰函数的时候,我们可以考虑用模拟退火来解决,当然这只能给我们骗更多的分,想通过的话有一定的难度。优点根据爬山算法的过程,我们发现,爬山算法只能看到当前的最优解,而如果后面又有更优的解,爬山算......
  • 基于SA模拟退火优化的TWVRP路径规划matlab仿真
    1.算法仿真效果matlab2022a仿真结果如下:2.算法涉及理论知识概要模拟退火算法(simulatedannealing,SAA)来源于固体退火原理,是一种基于概率的算法。模拟退火算法来源于固体退火原理,是一种基于概率的算法,将固体加温至充分高,再让其徐徐冷却,加温时,固体内部粒子随温升变为无序状,内能增......
  • 模拟退火算法—旅行商问题(TSP)优化 Matlab代码可用于路径规划,物流配送,路径优化
    模拟退火算法—旅行商问题(TSP)优化Matlab代码可用于路径规划,物流配送,路径优化源码+注释数据可以修改多少个坐标都行帮忙改数据就是另外的价钱[旺柴]代码一经售出概不退换!望理解ID:835675752236542......
  • GASA-BP基于遗传模拟退火优化BP神经网络的回归预测 案例包括GA与SA优化B
    GASA-BP基于遗传模拟退火优化BP神经网络的回归预测案例包括GA与SA优化BP代码,并给出对比计算结果matlab代码,备注详细,方便初学者学习ID:2530705617259360......
  • SA-BP模拟退火算法优化BP神经网络做时间序列预测,做多输入单输出系统的预测Matlab程序,
    SA-BP模拟退火算法优化BP神经网络做时间序列预测,做多输入单输出系统的预测Matlab程序,预测精度很高。ID:1985662031870152......
  • 模拟退火算法做路径规划,解决TSP问题。
    模拟退火算法做路径规划,解决TSP问题。ID:4360618365509805......
  • 模拟退火算法
    访问【WRITE-BUG数字空间】_[内附完整源码和文档]该项目主要是利用局部搜索算法(LS)和模拟退火算法(SA)解决TSP问题。先是使用LS求解TSP问题,再尝试SA问题,比较两者,在效率上SA更占有。最后再在LS的基础上使用SA,再优化SA部分算法,尝试求解TSP问题。选用的TSP测例为eil1......