题解:UVA1476 Error Curves 使用 SA 解决
Python_enjoy · · 题解
我们来分析一下这个题。
就这么说,虽然你能够用这个那个数学方法来证明出这是一个单峰函数,但是很多时候如果没有“三分”这个标签,你压根就想不出来这道题是单峰函数。
所以我们可以用模拟退火来解决这道题(调参调了一天)。
这道题因为较为简单,所以可以设置较为激进的降温策略。初始温度设置一个最平常的 4000 就可以了。
其他的就跟 SA 的模板是差不多的了。
AC 代码:
#include <bits/stdc++.h>
using namespace std;
const double down=0.9943; // 可以设置激进一点的降温速度
int n;
struct node{
double x,y,w;
}a[10005];
double dx,now;
double energy(double x)
{
double tot=-1e20; // 注意 f(x) 可能为负数
for(int i=1; i<=n; i++)
{
tot=max(tot,a[i].x*x*x+a[i].y*x+a[i].w);
}
return tot;
}
void SA()
{
double t=4000;
while(t>1e-17)
{
double tx=dx+(rand()*2-RAND_MAX)*t;
if(tx<0) tx=(rand()%100);
if(tx>1000) tx=(1000);
double temp=energy(tx);
double delte=temp-now;
if(delte<0)
{
dx=tx;
now=temp;
}
else if(exp(-delte/t)*RAND_MAX>rand())
{
dx=tx;
}
t*=down;
}
}
void sjk()
{
cin>>n;
for(int i=1; i<=n; i++)
{
cin>>a[i].x>>a[i].y>>a[i].w;
}
dx=500;
now=energy(dx);
SA();
cout<<fixed<<setprecision(4)<<energy(dx)<<endl;
}
int main()
{
int t;
cin>>t;
while(t--) sjk();
return 0;
}
但是我们悲催的发现,只有吸氧可以过这个代码,不然只有 50 分。
怎么办!
打正解?No way!
温度?
降温速度?
ACcode(不吸氧):
#include <bits/stdc++.h>
using namespace std;
const double down=0.885;
int n;
struct node{
int x,y,w;
}a[10005];
double dx,now;
double energy(double x)
{
double tot=-1e20;
for(int i=1; i<=n; i++)
{
tot=max(tot,a[i].x*x*x+a[i].y*x+a[i].w);
}
return tot;
}
void SA()
{
double t=3000;
while(t>1e-17)
{
double tx=dx+(rand()*2-RAND_MAX)*t;
if(tx<0) tx=0;
if(tx>1000) tx=(1000);
double temp=energy(tx);
double delte=temp-now;
if(delte<0)
{
dx=tx;
now=temp;
}
else if(exp(-delte/t)*RAND_MAX>rand())
{
dx=tx;
}
t*=down;
}
}
void sjk()
{
cin>>n;
for(int i=1; i<=n; i++)
{
cin>>a[i].x>>a[i].y>>a[i].w;
}
dx=500;
now=energy(dx);
SA();
cout<<fixed<<setprecision(4)<<energy(dx)<<endl;
}
int main()
{
int t;
cin>>t;
while(t--) sjk();
return 0;
}
最后,让我们以一段有趣的笑话来结尾吧
一段 模拟退火
一台 电脑
一个夜晚
一个又 WA 又 TLE 的记录
管理员大大求通过 QAQ