POJ2420 & HDU1109 模拟退火

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

*/




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值