模拟退火
模拟退火能解决三分这类的问题,当然能解决三分不能的(暂时还不太会)
它能求出单峰函数的极值。
具体实现:
时间t初值为区间大小,每次乘上delta,delta一般设为0.992333
每次改变位置(先大范围跳,在小范围跳),计算答案,如果更优就更新,不优就用一个概率去选择更新
void tui()
{
t=1000;//温度初值
while(t>1e-12)
{
X=x+(rand()*2-RAND_MAX)*t*0.0001;//改变位置
if(X1000)X=1000;//判断边界
now=suan(X);//计算答案
double anss=now-ans2;
if(anss<0.0){ans1=X;ans2=now;x=X;}//如果更优就更新
else if(exp(-anss/t)*RAND_MAX>rand())x=X;//用一个概率去选择更新
t=t*delta;//温度下降
}
} 重要:
然后,我们发现精度不够啊,没三分准,怎么办?
我们再枚举1000(.......)次的0.001(保留几位小数)
double xu=ans1;
double xjh=xu;
double XJH=0.0;
for(int i=1;i<=1000;i++)
{
xjh+=0.0001;
if(xjh>1000.0)break;
XJH=suan(xjh);
if(XJH<ans2)
{
ans1=xjh;
ans2=XJH;
}
}
xjh=xu;
XJH=0.0;
for(int i=1;i<=1000;i++)
{
xjh-=0.0001;
if(xjh<0.0)break;
XJH=suan(xjh);
if(XJH<ans2)
{
ans1=xjh;
ans2=XJH;
}
} 这样就能保证精度了,根据时间在多做几次退火即可。
为了使答案更加准确,我们可以先随机若干次,这样的话跳动会更加优秀。
for(int i=1;i<=3000;i++)
{
int X=rand()%n+1,Y=rand()%n+1;
int ret=calc(X,Y);
if(ret>ans)ans=ret,x=X,y=Y;
} 例题1:#10013. 「一本通 1.2 例 3」曲线
明明做作业的时候遇到了个二次函数,
,他突发奇想设计了一个新的函数 ,
明明现在想求这个函数在 的最小值,要求精确到小数点后四位,四舍五入。
题解:
这就是三分题,精度要求很高。
我们就用上面的方法,先退火,在暴力枚举确定答案。
代码:
#include
using namespace std;
//#define double long double
const int N=10005;
const double delta=0.9929;
int T,n;
double t,x,ans1,ans2,X,now,anss,k,kk,a[N],b[N],c[N];
double suan(double x)
{
k=a[1]*x*x+b[1]*x+c[1];
for(int i=2;i<=n;i++)
{
kk=a[i]*x*x+b[i]*x+c[i];
if(kk>k)k=kk;
}
return k;
}
void tui()
{
t=1000;
while(t>1e-12)
{
X=x+(rand()*2-RAND_MAX)*t*0.0001;
if(X1000)X=1000;
now=suan(X);
double anss=now-ans2;
if(anss<0.0){ans1=X;ans2=now;x=X;}
else if(exp(-anss/t)*RAND_MAX>rand())x=X;
t=t*delta;
}
}
void solve()
{
ans1=0.0;ans2=suan(x);
tui();
double xu=ans1;
double xjh=xu;
double XJH=0.0;
for(int i=1;i<=1000;i++)
{
xjh+=0.0001;
if(xjh>1000.0)break;
XJH=suan(xjh);
if(XJH<ans2)
{
ans1=xjh;
ans2=XJH;
}
}
xjh=xu;
XJH=0.0;
for(int i=1;i<=1000;i++)
{
xjh-=0.0001;
if(xjh<0.0)break;
XJH=suan(xjh);
if(XJH<ans2)
{
ans1=xjh;
ans2=XJH;
}
}
}
int main()
{
srand(19491001);srand(rand());srand(rand());
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%lf%lf%lf",&a[i],&b[i],&c[i]);
solve();
printf("%.4lf\n",ans2);
}
} 
京公网安备 11010502036488号