二至济南--随机化

\(update: 2025/9/20\)

随机化并不是作为一节课讲的,而是在一次机缘巧合中学到的

爬山算法

大抵是有了新欢便放弃了旧爱 (虽然我从未了解过爬山算法,毕竟我接触到的第一个随机化算法是退火)

模拟退火

随机化的一种算法,当一个问题的方案数极大且不是一个单峰函数时使用 (虽然我都在骗分中使用)

在爬山算法中,我们会舍去次解,但有时最优解由这些次解得到,而模拟退火会以一定概率接受这些次解,从而转移到更优的状态中

具体的,模拟退火分为以下几点

参数

有如下几个

  • \(T\) 温度
  • \(L\) 马尔可夫链长度(在同一温度下循环几次,下面代码循环为1所以没写)
  • \(lt\) 降温参数 ( 其实是\(\Delta T\) )
  • \(et\) 终止温度 ( \(T_{end}\) )
  • \(step\) 随机数范围
  • \(cur\) 当前保存的解
  • \(ans1\) 新解
  • \(ans\) 最终解

原谅作者的取名技术

接受准则

模拟退火中,用温度来反映当前状态的"活跃度",即接受劣解的概率,一般用\(Metropolis\)准则,如下(截取自OI_Wiki并改编):

\[P=\begin{Bmatrix} 1 & ans1\: is\: better\:than \: cur\\ e^{\frac{\Delta E}{T} } & else \end{Bmatrix} \]

其中,\(\Delta E\)是新解与保存解的差值(相对于更优而言,保证其为负数即可)

其他技巧

一个卡时小技巧 (截取自OI_Wiki)
clock()可以返回程序运行时间(毫秒),(double)clock()/CLOCKS_PER_SEC()是当前程序的用时(秒)

\(code\)
P4653 [CEOI 2017] Sure Bet

//May all the beauty be blessed.
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n;
double a[100010],b[100010],ans;

void sa(){
	double T=1e5,et=1e-7,lt=0.99997;//初始化
	
	int x=rand()%(n+1),y=rand()%(n+1);
	double cur=min(a[x]-x-y,b[y]-x-y); //先得出一个解
	while(T>et){
		int step=(int)(T/1e5*n)+1; //计算范围,其随着T的减小而降低
		int o=rand()%2;
		if(o){
			int x2=x+rand()%(2*step+1)-step;
			if(x2<0) x2=0;
			if(x2>n) x2=n;
			
			double ans1=min(a[x2]-x2-y,b[y]-x2-y);
			if(ans1>cur||exp((ans1-cur)/T)*RAND_MAX>rand()) x=x2,cur=ans1; //Metropolis准则
		}else{
			int y2=y+rand()%(2*step+1)-step;
			if(y2<0) y2=0;
			if(y2>n) y2=n;
			
			double ans1=min(a[x]-x-y2,b[y2]-x-y2);
			if(ans1>cur||exp((ans1-cur)/T)*RAND_MAX>rand()) y=y2,cur=ans1;
		}
		ans=max(ans,cur);
        //将上述代码运行L次(马尔可夫链长度),再降温
		T*=lt;
	}
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	srand(time(0));
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i]>>b[i];
	sort(a+1,a+n+1,greater<>());
	sort(b+1,b+n+1,greater<>());
	
	for(int i=1;i<=n;i++) a[i]+=a[i-1],b[i]+=b[i-1];
	
	while((double)clock()/CLOCKS_PER_SEC<1.95) sa();//卡时小技巧
	cout<<fixed<<setprecision(4)<<ans;//保留小数
}
posted @ 2025-07-23 18:36  破碎中永恒  阅读(6)  评论(0)    收藏  举报