一篇关于模拟退火的题解,abc157 F Yakiniku Optimization Problem

Posted axiomofchoice

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一篇关于模拟退火的题解,abc157 F Yakiniku Optimization Problem相关的知识,希望对你有一定的参考价值。

https://atcoder.jp/contests/abc157/tasks/abc157_f

大意:平面上有n个饼,每个饼有一个属性ci。一个饼的烤熟时间为到火源的欧几里得距离乘以ci。求在适当的位置放置一个火源后让至少k个饼烤熟的最短时间

正解:计算几何+二分答案

但是我正在学习模拟退火所以走上了不归路。。。

首先确定答案的范围和精度。为了保证正确率,运行时间当然越大越好,所以确定了降温系数(大约0.9999到0.99999之间)

模拟退火有个公式 (exp(-dfrac{KD}{T})),这个参数K我不会调呀,算了直接设为无穷大吧(感觉如果极值点比较少的话这么做也没事)

但是也有找到局部最优但不是全局最优的情况。我之前一直以为函数只有一个单峰,后来才发现错了,加了多次退火就立马过了就离谱

然后我加了一个神奇机制,一旦发生状态转移就回温一下。事实证明这个机制真的有用.jpg虽然我没怎么想通

最后的最后,那就是多交代码了,因为模拟退火毕竟是个随机算法

于是emmm:

技术图片

#include <bits/stdc++.h>
using namespace std;
#define repeat(i,a,b) for(int i=(a),_=(b);i<_;i++)
#define repeat_back(i,a,b) for(int i=(b)-1,_=(a);i>=_;i--)
#define mst(a,x) memset(a,x,sizeof(a))
#define fi first
#define se second
#define endl "
"
int cansel_sync=(ios::sync_with_stdio(0),cin.tie(0),0);
mt19937 rnd(chrono::high_resolution_clock::now().time_since_epoch().count());
const int N=61; typedef long long ll; const int inf=~0u>>2; const ll INF=~0ull>>2; ll read(){ll x; if(scanf("%lld",&x)==-1)exit(0); return x;} typedef double lf; const lf pi=acos(-1.0); lf readf(){lf x; if(scanf("%lf",&x)==-1)exit(0); return x;} typedef pair<int,int> pii;
const int mod=(999983); ll mul(ll a,ll b,ll m=mod){return a*b%m;} ll qpow(ll a,ll b,ll m=mod){ll ans=1; for(;b;a=mul(a,a,m),b>>=1)if(b&1)ans=mul(ans,a,m); return ans;}
//#define int ll
struct vec{
	lf x,y;
	explicit vec(lf x=0,lf y=0):x(x),y(y){}
	vec operator-(const vec &b){return vec(x-b.x,y-b.y);}
	vec operator+(const vec &b){return vec(x+b.x,y+b.y);}
	vec operator*(lf k){return vec(k*x,k*y);}
	lf len(){return hypot(x,y);}
	lf sqr(){return x*x+y*y;}
	vec trunc(lf k=1){return *this*(k/len());}
	vec rotate(double th){lf c=cos(th),s=sin(th); return vec(x*c-y*s,x*s+y*c);}
}a[N];
ostream &operator<<(ostream &o,const vec &v){return o<<‘(‘<<v.x<<‘,‘<<v.y<<‘)‘;}
int n,k; lf c[N],s[N];

lf E(vec v){
	repeat(i,0,n)s[i]=(a[i]-v).len()*c[i];
	nth_element(s,s+k,s+n);
	return s[k];
}

lf rndf(){return rnd()*1.0/rnd.max();}
vec rndvec(){return vec(rndf()*2-1,rndf()*2-1);}
struct state{
	vec v; lf e;
	state(vec v=vec()):v(v),e(E(v)){}
	operator lf(){
		return e;
	}
};
state solve(){
	state X; lf T=1000;
	auto work=[&](){
		state Y=X.v+rndvec()*T;
		if(Y<X){X=Y; return 1;}
		return 0;
	};
	while(T>1e-9){
		if(work()){
			work(); work();
			T*=1.1;
		}
		T*=0.99992;
	}
	return X;
}

void Solve(){
	n=read(),k=read()-1;
	repeat(i,0,n)a[i].x=read(),a[i].y=read(),c[i]=read();
	state X=solve();
	repeat(i,0,5){
		state Y=solve();
		if(X>Y)X=Y;
	}
	printf("%.10f
",lf(X));
}
signed main(){
	int T=1; //T=read();
	while(T--)Solve();
	return 0;
}

以上是关于一篇关于模拟退火的题解,abc157 F Yakiniku Optimization Problem的主要内容,如果未能解决你的问题,请参考以下文章

模拟退火

模拟退火算法

loj#2076. 「JSOI2016」炸弹攻击 模拟退火

OpenAI Gym 关于CartPole的模拟退火解法

OpenAI Gym 关于CartPole的模拟退火解法

BZOJ3680吊打XXX(模拟退火)