退役很久了,今天看一篇paper用SA算法代替随机梯度优化神经网络,故学习一波SA算法。
因为网上的资料很多,所以这里就不多说啦。
详情可以看https://www.cnblogs.com/rvalue/p/8678318.html
高中生太强啦
这里放一个模板~
题目链接:https://www.luogu.org/problemnew/show/P1337
P1337 [JSOI2004]平衡点 / 吊打XXX
题目描述
如图:有n个重物,每个重物系在一条足够长的绳子上。每条绳子自上而下穿过桌面上的洞,然后系在一起。图中X处就是公共的绳结。假设绳子是完全弹性的(不会造成能量损失),桌子足够高(因而重物不会垂到地上),且忽略所有的摩擦。
问绳结X最终平衡于何处。
注意:桌面上的洞都比绳结X小得多,所以即使某个重物特别重,绳结X也不可能穿过桌面上的洞掉下来,最多是卡在某个洞口处。
输入输出格式
输入格式:
文件的第一行为一个正整数n(1≤n≤1000),表示重物和洞的数目。接下来的n行,每行是3个整数:Xi.Yi.Wi,分别表示第i个洞的坐标以及第 i个重物的重量。(-10000≤x,y≤10000, 0<w≤1000 )
输出格式:
你的程序必须输出两个浮点数(保留小数点后三位),分别表示处于最终平衡状态时绳结X的横坐标和纵坐标。两个数以一个空格隔开。
输入输出样例
输入样例#1: 复制
3 0 0 1 0 2 1 1 1 1
输出样例#1: 复制
0.577 1.000
说明
[JSOI]
代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 1e4+10;
struct Point
{
double x,y;
Point(double x=0,double y=0)
{
this->x=x;
this->y=y;
}
}p[N];
int n;
double g[N];
Point ans;
double minAns=DBL_MAX;
double Rand()
{
return double(rand())/double(RAND_MAX);
}
double Sqr(double a)
{
return a*a;
}
double Eulc(Point A,Point B)
{
return sqrt(Sqr(A.x-B.x)+Sqr(A.y-B.y));
}
double Calc(Point A)
{
double ans=0;
for(int i=0;i<n;i++)
ans+=Eulc(A,p[i])*g[i];
if(ans<minAns)
{
::ans=A;
minAns=ans;
}
return ans;
}
bool Accept(double delta,double tmp)
{
return delta<0||Rand()<exp(-delta/tmp);
}
Point SimulatedAnnealing(Point init,double initT,double dec,double endT)
{
double tmp=initT;
Point now = init;
double nowAns=Calc(now);
while(tmp>endT)
{
Point next = Point(now.x+tmp*(2*Rand()-1),now.y+tmp*(2*Rand()-1));
double ans = Calc(next);
if(Accept(ans-nowAns,tmp))
{
nowAns=ans;
now=next;
}
tmp*=dec;
}
for(int i=0;i<10000;i++)
{
Point rnc = Point(ans.x+tmp*(2*Rand()-1),ans.y+tmp*(2*Rand()-1));
Calc(rnc);
}
return now;
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
Point init;
init.x=init.y=0.0;
for(int i=0;i<n;i++)
{
scanf("%lf %lf %lf",&p[i].x,&p[i].y,&g[i]);
init.x+=p[i].x,init.y+=p[i].y;
}
init.x/=n,init.y/=n;
SimulatedAnnealing(init,1e5,1-7e-3,1e-3);
printf("%.3lf %.3lf\n",ans.x,ans.y);
}
return 0;
}
能不能AC全看脸,启发式算法为了逼近全局最优解,其中包含有随机值。
当然实际使用中,我们往往并不需要最优解,而只要一个逼近最优解的值就行了。