来自FallDream的博客,未经允许,请勿转载,谢谢。
题意:T组数据,每次给定y,求F(x) = 6 * x^7+8*x^6+7*x^3+5*x^2-y*x (0 <= x <=100) 的最小值 T<=100
这题貌似是有正常解法的,就是求导之后二分 然而我不会求导 所以呢 上模拟退火
模拟退火呢 大概是说我有一个初始温度,并且以一定的比率衰减。对于每一个状态,向外扩展状态(温度越大扩展范围越大),如果它比目前的状态更优,那么就选择它,不然,以一定的比率接受它(显然答案越劣这个比率越小).
然后时间不会很卡,可以多退火几次,比较稳健,但是它的常数还是挺大的233...
#include<iostream> #include<cstdio> #include<ctime> #include<cmath> #include<algorithm> #define INF 1e18 #define T 100 #define delta 0.98 #define eps 1e-8 #define IT 5 using namespace std; int qq; double ans; inline double calc(double x,double y) { double sq=x*x,cube=x*x*x; return 6*cube*cube*x+8*cube*cube+7*cube+5*sq-y*x; } inline double Ran(){return (double)rand()/(double)RAND_MAX;} bool check(double x){return x+eps>0&&x<100+eps;} double search(double y) { double x=Ran()*100,res=calc(x,y),t=T; while(t>eps) { for(int j=1;j<=IT;j++) { double nx=x+(rand()&1?1:-1)*Ran()*t; if(check(nx)) { double th=calc(nx,y); if(th<res||Ran()>=exp(-th/res)) res=th,x=nx; } } t*=delta; } return res; } int main() { srand(20170415U); for(cin>>qq;qq;--qq) { double y;ans=INF; scanf("%lf",&y); for(int i=1;i<=IT;i++) ans=min(ans,search(y)); printf("%0.4lf ",ans); } return 0; }