一些求解极值的问题不能通过函数特性直接求解,只能暴力枚举,但是单纯的枚举效率不高,通过模拟退火算法可以高效的找到答案。
相关题目:
最小圆覆盖:
hdu 3007
Buried memory
大意:给出一些点,求出能覆盖他们的最小的圆。输出圆心和半径
本想尝试做三分题,zoj 3421 Error Curves,但是发现不是超时,就是WA。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
const double eps=1e-7,INF=1e99; // T: 初始温度 delta:下降速率
const double T=10,delta=0.88; //一般地,T=100, delta=0.98
const int N=5e2+10;
struct point{
double x,y;
}p[N],s;
double dis(point a,point b){
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
double solve(int n){
s=p[0];
double t=T;
double r=INF;
while(t>eps){
int k=0;
double d=0;
for(int i=0;i<n;i++){
double f=dis(s,p[i]);
if(f>d){
d=f;
k=i;
}
}
s.x+=(p[k].x-s.x)/d*t;
s.y+=(p[k].y-s.y)/d*t;
r=min(r,d);
t*=delta;
}
return r;
}
int main()
{
int n;
while(~scanf("%d",&n)&&n){
for(int i=0;i<n;i++){
scanf("%lf %lf",&p[i].x,&p[i].y);
}
double r=solve(n);
printf("%.2lf %.2lf %.2lf\n",s.x,s.y,r);
}
return 0;
}
最小球包含
POJ 2069 Super Star
大意:给出一些三维空间的点,求最小的包含他们的球的半径
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
const double T=100,delta=0.98; //下降速度一般设成0.98
const double eps=1e-7,INF=1e99;
struct point{
double x,y,z;
}p[35],s;
double dis(point a,point b){
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)+(a.z-b.z)*(a.z-b.z));
}
double solve(int n){
s=p[0];
double t=T;
double ans=INF;
while(t>eps){
int k=0;
for(int i=0;i<n;i++){
if(dis(s,p[i])>dis(s,p[k])){
k=i;
}
}
double d=dis(s,p[k]);
ans=min(ans,d);
s.x+=(p[k].x-s.x)/d*t; //向量
s.y+=(p[k].y-s.y)/d*t;
s.z+=(p[k].z-s.z)/d*t;
t*=delta;
}
return ans;
}
int main()
{
int n;
while(cin>>n&&n){
for(int i=0;i<n;i++){
scanf("%lf%lf%lf",&p[i].x,&p[i].y,&p[i].z);
}
printf("%.5lf\n",solve(n));
}
return 0;
}
查找函数极值:
hdu 2899
Strange fuction
求解: F(x) = 6 * x^7+8*x^6+7*x^3+5*x^2-y*x (0 <= x <=100) 的最小值
#include <iostream>
#include <cstdio>
#include <cmath>
#include <stdlib.h>
#include <algorithm>
using namespace std;
const double eps=1e-7,INF=1e99;
const double T=100,delta=0.88; // 0.98 太慢了
const int N=10;
double x[N];
double random(){
double x=rand()*1.0/RAND_MAX;
if(rand()&1) x=-x;
return x;
}
int jud(double a,double b){
if(fabs(a-b)<eps) return 0;
if(a-b<-eps) return -1;
return 1;
}
double calc(double x,double y){
return 6*pow(x,7)+8*pow(x,6)+7*pow(x,3)+5*x*x-y*x;
}
double solve(double y){
for(int i=0;i<N;i++) x[i]=fabs(random()*100);
double ans=INF;
double t=T;
while(t>eps){
for(int i=0;i<N;i++){ // change x[i]
double temp=calc(x[i],y);
for(int j=0;j<N;j++){ //times
double xx=x[i]+random()*t;
if(jud(xx,0)>=0 && jud(xx,100)<=0){
if(jud(temp,calc(xx,y))>0){
x[i]=xx;
break;
}
}
}
}
t=t*delta;
}
for(int i=0;i<N;i++) ans=min(ans,calc(x[i],y));
return ans;
}
int main()
{
int t;
double y;
cin>>t;
while(t--){
scanf("%lf",&y);
printf("%.4lf\n",solve(y));
}
return 0;
}
/*
%.4lf\n
2
100
-74.4291
200
-178.8534
-------------
%lf\n
2
100
-74.429122
200
-178.853367
*/
本想尝试做三分题,zoj 3421 Error Curves,但是发现不是超时,就是WA。