n局部搜索,模拟退火,遗传算法,禁忌搜索的形象比喻:为了找出地球上最高的山,一群有志气的兔子们开始想办法。
1.兔子朝着比现在高的地方跳去。他们找到了不远处的最高山峰。但是这座山不一定是珠穆朗玛峰。这就是局部搜索,它不能保证局部最优值就是全局最优值。
2.兔子喝醉了。他随机地跳了很长时间。这期间,它可能走向高处,也可能踏入平地。但是,他渐渐清醒了并朝最高方向跳去。这就是模拟退火。
3.兔子们吃了失忆药片,并被发射到太空,然后随机落到了地球上的某些地方。他们不知道自己的使命是什么。但是,如果你过几年就杀死一部分海拔低的兔子,多产的兔子们自己就会找到珠穆朗玛峰。这就是遗传算法。
4.兔子们知道一个兔的力量是渺小的。他们互相转告着,哪里的山已经找过,并且找过的每一座山他们都留下一只兔子做记号。他们制定了下一步去哪里寻找的策略。这就是禁忌搜索。
上面是网上关于模拟退火的一些很形象的描述~~
POJ2420
题意:给n个点,在平面内选一个点,使得到所有点的距离和最小,求最小距离。
选定点肯定在各个相邻点相连的多边形的内部,在区域内退火就好了
注意POJ 上调用时间函数在g++上会RE。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<time.h>
const int N = 30;
const double T_min = 1e-2;
const double INF = 1e9;
const double K = 0.25 ;
const double PI = acos(-1.0);
using namespace std;
int n;
double X1 , Y1 , X2 , Y2;
double dis[35];
inline double Rand(double r,double l)
{
return ( rand() % ((int)(l-r)*1000) ) / (1000 + r) ;
}
struct point
{
double x,y;
point(){};
point(double _x,double _y):x(_x),y(_y){}
}P[100],people[35];
inline double D (point a, point b)
{
return sqrt( pow(a.x-b.x,2) + pow(a.y-b.y , 2) );
}
inline double oper (point a )
{
double d = 0 ;
for(int i=1;i<=n;i++)
d += D( a,P[i] );
return d ;
}
inline void init()
{
for(int i=1;i<=N ;i++)
{
people[i].x = Rand(X1,X2);
people[i].y = Rand(Y1,Y2);
dis[i] = oper(people[i]) ;
}
}
inline bool judge (point a){
return (a.x>=X1 && a.x <= X2 && a.y >= Y1 && a.y <=Y2 );
}
int main()
{
srand(time(NULL));
while(scanf("%d",&n) == 1 )
{
X1 = Y1 = INF ; // min x , y
X2 = Y2 = 0 ; // max x , y
for(int i=1;i<=n;i++)
{
scanf("%lf %lf",&P[i].x,&P[i].y);
X1 = min(X1 , P[i].x );
Y1 = min(Y1 , P[i].y );
Y2 = max(Y2 , P[i].y );
X2 = max(X2 , P[i].x );
}init();
double T_now = max(X2-X1 , Y2-Y1);
while(T_now > T_min)
{
for(int i=1;i<=N;i++)
{
for(int t=1;t<=N;t++)
{
double angle = Rand (0, 2*PI );
point tmp(people[i].x+cos(angle)*T_now,people[i].y+sin(angle)*T_now);
if(!judge(tmp))continue;
int d = oper(tmp);
if(d <= dis[i])
{
dis[i] = d;
people[i] = tmp ;
}
}
}
T_now *= K ;
}
double ans = INF;
for(int i=1;i<=N;i++)
ans = min(ans,dis[i]);
printf("%.0f\n",ans+0.5);
}
}
HDU1109
题意:给一个矩阵的长宽,再给n个点,求矩阵区域内某个点到各个点的最小距离的最大值,输出所求点的坐标
poj上好像有一道一样的题但是好像数据会强一点。在区域内模拟退火就好了
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<ctime>
#include<cmath>
using namespace std;
const double k = 0.55; // 退火常系数
const double T_min = 1e-3; // 退火下界
const double INF = 999999999;
const double PI = acos(-1.0);
const int N = 30 ; // 退火数
int X,Y,n;
double dis[1005]; //评估函数
struct point
{
double x,y;
}P[1005],people[35];
inline double Rand(double r,double l){
return (rand()% ((int)(l-r)*1000) ) / (1000.0+r);
}
inline double D( point a,point b){
return sqrt( pow((a.x-b.x),2) + pow((a.y-b.y),2) );
}
inline bool judge(point a){
return ( a.x>=0 && a.x<=X && a.y>=0 && a.y<=Y );
}
inline double oper ( point a){
double d = INF ;
for(int i=1;i<=n;i++)
d = min (d , D( a,P[i] ));
return d ;
}
int main()
{
int T;srand(time(0));
scanf("%d",&T);
while(T--)
{
scanf("%d%d%d",&X,&Y,&n);
for(int i=1;i<=n;i++)
scanf("%lf%lf",&P[i].x,&P[i].y);
for(int i=1;i<=N ; i++)
{
people[i].x = Rand(0,X*1.0);
people[i].y = Rand(0,Y*1.0);
dis[i] = oper(people[i]);
}
double T_now = max(X,Y);
while( T_now > T_min )
{
//printf("T_now = %.5f\n",T_now);
for(int i=1;i<=N;i++)
{
for(int t=1;t<=50;t++)
{
double angle = Rand(0,2*PI);
point tem ;
tem.x = people[i].x + cos(angle)*T_now ;
tem.y = people[i].y + sin(angle)*T_now ;
if(!judge(tem))continue ;
double d = oper(tem);
if( d >= dis[i] )
{
dis[i] = d;
people[i] = tem ;
}
}
}
T_now *= k ;
}
int ans = 1;
for(int i=2;i<=N;i++)
if(dis[i]>dis[ans])
ans = i;
printf("The safest point is (%.1f, %.1f).\n",people[ans].x,people[ans].y);
}return 0;
}
/**
3
1000 50 1
10 10
100 100 4
10 10
10 90
90 10
90 90
3000 3000 4
1200 85
63 2500
2700 2650
2990 100
*/