模拟退火要求:
1. 初始温度足够高
2. 降温过程足够慢
3. 终止温度足够低
TSP 问题: 这是一个 NP 完全问题 大型实例不能用精确解去算,必须寻求有效的近似算法。
模拟退火算法在神经网计算机中的应用模拟退火算法具有跳出局部最优陷阱的能力。
在Boltzmann机中,即使系统落入了局部最优的陷阱,
经过一段时间后,它还能再跳出来,再系统最终将往全局最优值的方向收敛。
初始降温参数和eps需要自己调参
#include <cmath>
#include <cstdio>
#include <cstring>
#include <ctime>
using namespace std;
const int N = 1e5 + 7;
int n, x[N], y[N], w[N];
double ansx, ansy, dist;
double Rand() { return (double)rand() / RAND_MAX; }
double get_dist(double xx, double yy){
double res = 0;
for (int i = 1; i <= n; ++i) {
double dx = x[i] - xx, dy = y[i] - yy;
res += sqrt(dx * dx + dy * dy) * w[i];
}
// if(res < dist) dist = res, ansx = xx, ansy = yy;
return res;
}
void simulateAnneal(){
double T = 1e5; // 初始温度要足够大
double eps = 1e-3; // 结束温度足够低
double down = 0.97; // 降温时间足够长
double nowx = ansx, nowy = ansy;
while(T > eps){
// 随机 计算数值
double nxtx = nowx + T * (Rand() * 2 - 1);
double nxty = nowy + T * (Rand() * 2 - 1);
double delta = get_dist(nxtx, nxty) - get_dist(nowx, nowy);
if(delta < 0) nowx = nxtx, nowy = nxty, dist = dist + delta;
else if(exp(- delta / T) > Rand()) nowx = nxtx, nowy = nxty; // 概率接受正解
T *= down;
}
ansx = nowx, ansy = nowy;
for (int i = 1; i <= 1000; ++i) {
double nxtx = ansx + T * (Rand() * 2 - 1);
double nxty = ansy + T * (Rand() * 2 - 1);
double z = get_dist(nxtx, nxty);
if(z < dist) dist = z, ansx = nxtx, ansy = nxty;
}
}
int main() {
srand(time(0));
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, dist = get_dist(ansx, ansy);
// 模拟退火
simulateAnneal();
printf("%.3lf %.3lf\n", ansx, ansy);
return 0;
}
最下面是啥啊?
ok了 图片出问题了
为什么名字叫luogu?
懒得起名字了,hh
这个名字没事,在分享里搜模拟退火还是可以搜到的
2333333333333333333333333333333333333333333333333333333333333333