模拟退火 poj3422 run away

来源:互联网 发布:视频人脸打马赛克软件 编辑:程序博客网 时间:2024/05/21 07:09

题目 http://poj.org/problem?id=1379

题目大意 :平面上有n个点,然后在平面上找一个位置(x,y),使得(x,y)n各点的最短距离

尽量大。

算法 :模拟退火。

思路 :设距离是D,则D  = min{  sqrt((x – p[i].x)^2 +(y – p[i].y)^2) } 是一个三元函数最值

的问题。由于没有明显的单调性,因此分治算法不太好用, 只能用模拟退火了。下面给出

模拟退火算法流程。

1 :在平面内随机生成若干个点             (蒙特卡洛算法思想)

2 :确定火的最大温度t,及递减程度(退火比例)

3 :对于每一个温度,枚举1中的若干个点

4 :对于每个点,进行(p – t, p +t)区间内的随机变化得到新点(x1,y1)。

5 :若新点优于旧点,则将新点替换为新点。

6 :回到2,直到温度低到要求精度。

7 :输出一开始随机的若干点中的最好解。

 

提交情况 time limit error1 次, 随机点的个数及点在指定温度内的变化次数增加

          Accepted 1

收获 :学习了三大随机算法之一的模拟退火算法。 但是还是简单版。有待提升

ACcode

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <math.h>

#include <time.h>

 

#define MAXM 1010

#define _P 50      //粒子的个数

#define _Times 40  // 每个粒子的运动次数

 

typedef doublereal;

 

structPOINT_NODE{  // 坐标点结构体

   real x, y;

};                

 

structANS_NODE{

   POINT_NODE pt;  // 当前解的位置

   real distance;  // 当前解的函数值

};               // 解的结构体

 

ANS_NODE ANS[_P];

POINT_NODE point[MAXM];

 

real X, Y;

int M;

 

real Rand_real(inta, int b){

   return (real)((rand()<< 14) ^ rand()) * (b - a) / (real)(1<< 29) + a;

}//随机取得a~b之间的一个实数

real evaluate(POINT_NODE p){

   real min = 100000.0, dis, dx, dy;

   for(int i = 0; i < M; i++){

      dx = p.x - point[i].x;

      dy = p.y - point[i].y;

      dis = sqrt(dx * dx + dy * dy);

      min = min < dis ? min : dis;

   }

   return min;

}//¨¤?¡¥ºy

 

ANS_NODE Get_ANS(real x1, real x2, real y1, realy2){

   ANS_NODE tem;

   tem.pt.x = Rand_real((x1 < 0.0 ? 0.0 : x1), (x2> X ? X : x2));

   tem.pt.y = Rand_real((y1 < 0.0 ? 0.0 : y1), (y2> Y ? Y : y2));

   tem.distance = evaluate(tem.pt); // 求新解的评估值

   return tem;

}//用给定的范围随机生成一个解

 

int main(){

   int CASE, i, j;

   real temperature;

   ANS_NODE temp;

   scanf("%d",&CASE);

   srand(time(NULL));

   while(CASE --){

      scanf("%lf %lf %d",&X, &Y,&M);

      for(i = 0; i < M; i++)

          scanf("%lf %lf",&point[i].x,&point[i].y);

      for(i = 0; i < _P; i++)

          ANS[i] = Get_ANS(0.0, X, 0.0, Y);  // ?¨²¨²¦¨² _P ?a

 

      for(temperature = sqrt(X * X + Y *Y) * 0.6; temperature > 0.001; temperature *=0.8) // 初始温度为矩形对角线的0.6倍,递减为0.8

          for(i = 0; i < _P; i++)

             for(j = 0; j <_Times; j ++){

                 temp = Get_ANS(ANS[i].pt.x - temperature, ANS[i].pt.x +temperature, ANS[i].pt.y - temperature, ANS[i].pt.y +temperature);

                 if(temp.distance >ANS[i].distance) ANS[i] = temp;

             }

      for(i = j = 0; i <_P; i ++)

          if(ANS[i].distance >ANS[j].distance) j = i;

      printf("The safest point is (%.1lf,%.1lf).\n", ANS[j].pt.x, ANS[j].pt.y);

   }

   return 0;

}

 

原创粉丝点击