随机算法_模拟退火

参考:https://blog.csdn.net/niiick/article/details/82708589
参考:https://blog.csdn.net/m0_37579232/article/details/85057190

爬山算法

比如我要求一个函数在区间的最大值,
我开始会在这个区间内随机选几个点,然后挑最大的,
接下来在最大的点的附近又开始随机选几个点,然后再挑最大的
以此循环,最终是可以找到满足精度要求的

盘山算法实际上就是贪心,所以它满足局部最优解,但不一定满足全局最优解

在这里插入图片描述
我们想要的最终答案是A
爬山算法最终可能会得到B

模拟退火

为了解决爬山算法的不足
模拟退火会以一定概率接受一个非更优解

在这里插入图片描述
假如当前记录的最优解为B
随机到的下一个点为C
爬山算法会直接否定了这个点,但模拟退火决定以一定概率去接受
这样得到最终全局最优解A的概率就大大增加

模拟算法的描述是这样的:
若移动后得到更优解,则总是接受该移动
若移动后的解比当前解要差,则以一定的概率接受移动,而且这个概率随着时间推移逐渐降低。

这里的一定的概率的计算参考了金属冶炼的退火过程,这也是模拟退火算法名称的由来。
在 温 度 为 T 的 情 况 下 出 现 一 次 能 量 差 为 Δ E 的 降 温 的 概 率 为 在温度为T的情况下出现一次能量差为ΔE的降温的概率为 TΔE
P ( d E ) = e x p ( d E / ( k T ) ) P(dE) = exp( dE/(kT) ) P(dE)=exp(dE/(kT))
说白了就是:温度越高,出现一次能量差为dE的降温的概率就越大;温度越低,则出现降温的概率就越小。又由于dE总是小于0(否则就不叫退火了),因此dE/kT < 0 ,所以P(dE)的函数取值范围是(0,1) 。
随 着 温 度 T 的 降 低 , P ( d E ) 会 逐 渐 降 低 。 随着温度T的降低,P(dE)会逐渐降低。 TP(dE)

例题

Strange fuction
题意: F ( x ) = 6 ∗ x 7 + 8 ∗ x 6 + 7 ∗ x 3 + 5 ∗ x 2 − y ∗ x ( 0 < = x < = 100 ) F(x) = 6 * x^7+8*x^6+7*x^3+5*x^2-y*x (0 <= x <=100) F(x)=6x7+8x6+7x3+5x2yx(0<=x<=100)
给 你 y 让 你 求 m i n F ( x ) 给你y 让你求min F(x) yminF(x)

AC code
/*
Strange fuction
HDU - 2899
https://cn.vjudge.net/problem/HDU-2899
题意: F(x) = 6 * x^7+8*x^6+7*x^3+5*x^2-y*x (0 <= x <=100) 给你y求最小值
解法 模拟退火
*/
#include <bits/stdc++.h>
using namespace std;
#define T 100.0
#define delta 0.999
#define eps 1e-8
double y,dx[2]={1.0,-1.0};
double F(double x){
	return 6.0*pow(x,7.0)+8.0*pow(x,6.0)+7.0*pow(x,3)+5.0*pow(x,2.0)-y*x;
}
int main(){
	int Q;
	cin>>Q;
	while(Q--){
		cin>>y;
		double t=T,x=100.0,ans=F(x);
		while(t>eps){
			double nx=-1.0;
			while(nx<0||nx>100) nx=x+dx[rand()%2]*t;
			double de=ans-F(nx);
			if(de>=0) x=nx,ans=F(nx);
			else if(exp(de/t)>(double)rand()/(double)RAND_MAX) x=nx;
			t*=delta;
		}
		printf("%.4lf\n", ans);
	}
	return 0;
}

/*
Strange fuction
HDU - 2899
https://cn.vjudge.net/problem/HDU-2899
题意: F(x) = 6 * x^7+8*x^6+7*x^3+5*x^2-y*x (0 <= x <=100) 给你y,求F(x)最小值
解法: 爬山算法
*/
#include <bits/stdc++.h>
using namespace std;
#define T 100.0
#define delta 0.999
#define eps 1e-8
double y,dx[2]={1.0,-1.0};
double F(double x){
	return 6.0*pow(x,7.0)+8.0*pow(x,6.0)+7.0*pow(x,3)+5.0*pow(x,2.0)-y*x;
}
int main(){
	int Q;
	cin>>Q;
	while(Q--){
		cin>>y;
		double t=T,x=100.0,ans=F(x);
		while(t>eps)
		{
			double nx=-1.0;
			while(nx<0||nx>100) nx=x+dx[rand()%2]*t;
			if(F(nx)<F(x)) x=nx;
			t*=delta;
	}
	printf("%.4lf\n",F(x));
	}
	return 0;
}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值