专栏文章
【模板】三分 | 函数 使用 SA 解决
P1883题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @min4c9uj
- 此快照首次捕获于
- 2025/12/01 20:21 3 个月前
- 此快照最后确认于
- 2025/12/01 20:21 3 个月前
我们来分析一下这个题。
就这么说,虽然你能够用这个那个数学方法来证明出这是一个单峰函数,但是很多时候如果没有“三分”这个标签,你压根就想不出来这道题是单峰函数。
所以我们可以用模拟退火来解决这道题(调参调了一天)。
这道题因为较为简单,所以可以设置较为激进的降温策略。初始温度设置一个最平常的 4000 就可以了。
其他的就跟 SA 的模板是差不多的了。
AC 代码:
CPP#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(不吸氧):
CPP#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 的记录
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...