[JSOI2004] 平衡点 / 吊打XXX

前言

退火入门题,这篇是给自己看的博客,想学退火还是去其它博客吧。

题目

洛谷

讲解

退火,其实就是随机乱搞。对于普通的随机乱搞,我们只停留在如果更优就更新答案这个简单层面上,而这个其实就有个算法名字了:爬山。

而退火就是对爬山法的优化,对于一个当前随机出来的状态,如果它没有当前最优答案更优,令其与答案的估价函数的差值为 \(\Delta f(x)\),那么我们接受这个劣解的概率为 \(e^{\frac{\Delta f(x)}{kT}}\),其中 \(k\) 是一个常数,而 \(T\) 是当前的温度,在现实中温度越高表示金属越活跃,而在这里则表示步数之类的东西跨度大,\(T\) 以一个设定的常数逐级递减,这个常数一般设置为 \(0.9+\)

其实退火感觉就像随机化的 \(A^*\) 算法。

回到这道题,估价函数直接设置为距离乘以权值的和,当然设置为向量和也行,效果就是一个点在平面内到处跑。

时间复杂度?建议掐表,当然我只是建议。

代码

//12252024832524
#include <bits/stdc++.h>
#define TT template<typename T>
using namespace std; 

typedef long long LL;
const int MAXN = 1005;
const long double eps = 0.0001;
int n;

LL Read()
{
	LL x = 0,f = 1;char c = getchar();
	while(c > '9' || c < '0'){if(c == '-')f = -1;c = getchar();}
	while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
	return x * f;
}
TT void Put1(T x)
{
	if(x > 9) Put1(x/10);
	putchar(x%10^48);
}
TT void Put(T x,char c = -1)
{
	if(x < 0) putchar('-'),x = -x;
	Put1(x); if(c >= 0) putchar(c);
}
TT T Max(T x,T y){return x > y ? x : y;}
TT T Min(T x,T y){return x < y ? x : y;}
TT T Abs(T x){return x < 0 ? -x : x;}

mt19937 rd(time(0));
LL Rand(LL l,LL r){return (rd()%(r-l+1)+l);}

struct node{int x,y,w;}p[MAXN];
long double X,Y,ans,ansx,ansy,now;
long double sq(long double x){return x * x;}
long double calc(long double x,long double y)
{
	long double ret = 0;
	for(int i = 1;i <= n;++ i) ret += sqrt(sq(p[i].x-x)+sq(p[i].y-y)) * p[i].w;
	return ret;
}

int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	uniform_real_distribution<> realnum(0,1);
	n = Read();
	for(int i = 1;i <= n;++ i) p[i].x = Read(),p[i].y = Read(),p[i].w = Read(),X += p[i].x,Y += p[i].y;
	ansx = X = X/n; ansy = Y = Y/n; ans = now = calc(X,Y);
	for(int tim = 1;tim <= 1;++ tim)
		for(long double T = 1000000;T > eps;T *= 0.9996)
		{
			long double nx = X + Rand(-10,10) * T,ny = Y + Rand(-10,10) * T;
			long double cur = calc(nx,ny);
			if(cur < ans) ansx = X = nx,ansy = Y = ny,ans = now = cur;
			else if(exp(-(cur-ans)/T) >= realnum(rd)) X = nx,Y = ny,now = cur;
		}
	printf("%.3Lf %.3Lf\n",ansx,ansy);
	return 0;
}
posted @ 2022-02-21 20:18  皮皮刘  阅读(37)  评论(1编辑  收藏  举报