• 模拟退火算法实例(c++ 与 c# 实现)


    此片文章主要参考CSDN博主里头的一篇文章, 将自己的理解写下来,以方便后期的查阅。

     一、C++ 实现

    1. 已知平面上若干点坐标(xi, yi), 求平面上一点p(x, y) , 到这些点的总距离最小。

    思路: 取所有点的均值为目标点。计算全部点与目标点求差值的和,将目标点以一定系数朝着总和的方向移动,得到新的目标点。

     1 // 求最小距离
     2 // 限制条件: 1 <= n <= 100, 0<= xi, yi <= 1e4
     3 #include<iostream>
     4 #include<cstdio>
     5 #include<cdtdlib>
     6 #include<cmatch>
     7 
     8 using namespace std;
     9 
    10 struct Pt{
    11     double x, y;
    12 }P[105]
    13 
    14 double sqr(double x) {
    15     return x*x
    16 }
    17 
    18 // get distance between two point
    19 double dist(Pt a, Pt b)
    20 {
    21     return sqrt(sqr(a.x - b.x) + sqr(a.y - b.y));
    22 }
    23 
    24 double get_sum(Pt p0, int n)
    25 {
    26     double ret = 0;
    27     for(int i = 0; i < n; ++i)
    28         ret += dist(p0, p[i]);
    29 
    30 
    31 int main
    32 {
    33     // 设置初始化点数据
    34     // p[n] = { ... ,..., ....}
    35     // 取所有点的平均位置,作为最近点的位置
    36     double x0=0, y0 =0;
    37     for(int i = 0; i < n; ++i)
    38     {
    39         x0 += p[i].x;
    40         y0 += p[i].y;
    41     }
    42     x0 /= n;
    43     y0 /= n;
    44 
    45     double ans = get_sum((pt){x0, y0}, n); // 当前 目标值
    46     double temp = le5;  // 初始化温度, 根据需要设定
    47 
    48     while(temp > 0.02)  // 0.02 为温度的下限, 若温度为 temp 达到下限, 则停止搜索
    49     {
    50         double x = 0, y = 0;
    51         for(int i = 0; i < n; ++i) { // 获取步长的规则根据要求设定
    52             x += (p[i].x - x0) / dist((Pt){x0, y0}, p[i]);
    53             y += (p[i].x - y0) / dist((Pt){x0, y0}, p[i]);
    54         }
    55         // 变化后,新的目标值
    56         // 此处变化的系数应该是逐渐减小的, temp 逐渐减小,符合要求
    57         double tmp = get_sum((Pt){x0 + x * temp, y0 + y * temp}, n); 
    58 
    59         // 进行判断
    60         if(temp < ans)
    61         {
    62             ans = temp;
    63             x0 += x * temp;
    64             y0 += y * temp;
    65         }
    66         // 退火算法的精髓 : 当不满足移动条件时, 也按照一定的概率进行移动
    67         // 注意 : 移动的概率应该逐渐减小  
    68         // e n次幂, n 应该小于0
    69         //  假设 random() 的作用 : 产生 0- 1 之间的随机数
    70         else if(Math.exp((ans - temp) / temp) > random())
    71         {
    72             ans = temp;
    73             x0 += x * temp;
    74             y0 += y * temp;
    75         }
    76         temp *= 0.98; // 0.98 为降火速率(范围为0~1, 数字越大,得到的全局最优解概率越高,运行时间越长)
    77     }
    78     printf("The minimal dist is : ");
    79     printf("%.0f
    ", ans);
    80 }

    二、C# 实现代码

    已知空间上若干点(xi, yi, zi), 求空间上包含这些点的最小球半径 R, 以及球心坐标。

    思路:球心与这些点的最大距离为半径, 球心与最大距离点生成向量,将球心朝着该向量方向移动若干距离,再计算半径的变化。

      1 namespace Test_BST
      2 {
      3     public class Program
      4     {
      5         static void Main(string[] args)
      6         {
      7             // 初始化输入点
      8             List<Point> originPoints = new List<Point>() { ............};
      9             double radius = AnnealAlgorithm(originPoints);
     10         }
     11 
     12         private struct Point
     13         {
     14             public double x;
     15             public double y;
     16             public double z;
     17         }
     18 
     19         // square of a number
     20         private static double Sqr(double x) { return x * x; }
     21 
     22         // 两点之间的距离
     23         private static double Dist(Point A, Point B)
     24         {
     25             return Math.Sqrt(Sqr(A.x - B.x) + Sqr(A.y - B.y) + Sqr(A.z - B.z));
     26         }
     27 
     28         // 求最大半径
     29         private static double GetMaxRadius(Point p0, List<Point> pts)
     30         {
     31             double maxRadius = 0;
     32             foreach (var point in pts)
     33             {
     34                 double radius = Dist(p0, point);
     35                 maxRadius = radius > maxRadius ? radius : maxRadius;
     36             }
     37 
     38             return maxRadius;
     39         }
     40 
     41         private static double AnnealAlgorithm(List<Point> originPts)
     42         {
     43             Point center = new Point();
     44             center.x = 0;
     45             center.y = 0;
     46             center.z = 0;
     47 
     48             // 将初始化中心点设置为所有点的代数平均位置
     49             foreach (var pt in originPts)
     50             {
     51                 center.x += pt.x;
     52                 center.y += pt.y;
     53                 center.z += pt.z;
     54             }
     55             center.x /= originPts.Count;
     56             center.y /= originPts.Count;
     57             center.z /= originPts.Count;
     58 
     59             double temp = 1e3; // 初始温度
     60             double coolingFactor = 0.98; // 降温因子
     61             double ans = GetMaxRadius(center, originPts); // 当前最小半径
     62             var random = new Random();
     63 
     64             while (temp > 1e-5)
     65             {
     66                 Point newCenter = new Point();
     67                 double max_r = 0;
     68                 // 找到与当前中心点距离最远的点,将中心向着改点移动
     69                 for (int i = 0; i < originPts.Count; i++)
     70                 {
     71                     double r = Dist(center, originPts[i]);
     72                     if (r > max_r)
     73                     {
     74                         newCenter.x = (originPts[i].x - center.x) / r;
     75                         newCenter.y = (originPts[i].y - center.y) / r;
     76                         newCenter.z = (originPts[i].z - center.z) / r;
     77                         max_r = r;
     78                     }
     79                 }
     80                 newCenter.x = center.x + newCenter.x * temp;
     81                 newCenter.y = center.y + newCenter.y * temp;
     82                 newCenter.z = center.z + newCenter.z * temp;
     83 
     84                 // 移动后的最大半径
     85                 double tmp = GetMaxRadius(newCenter, originPts);
     86 
     87                 if (tmp < ans) 
     88                 {
     89                     center.x += newCenter.x * temp;
     90                     center.y += newCenter.y * temp;
     91                     center.z += newCenter.z * temp;
     92                 }
     93                 else if (Math.Exp((ans -tmp)/temp) > random.NextDouble() )
     94                 {
     95                     center.x += newCenter.x * temp;
     96                     center.y += newCenter.y * temp;
     97                     center.z += newCenter.z * temp;
     98                 }
     99 
    100                 temp *= coolingFactor;
    101             }
    102             double miniRadius = GetMaxRadius(center, originPts);
    103             Console.WriteLine("the cooridnate of the center is {0}, the radius value is {1}", center, miniRadius));
    104 
    105             return miniRadius;
    106         }
    107     }
    108 }

     参考: http://blog.csdn.net/whai362/article/details/46980471#comments

  • 相关阅读:
    【STM32F407开发板用户手册】第8章 STM32F407的终极调试组件Event Recorder
    【STM32F429开发板用户手册】第7章 STM32F429下载和调试方法(IAR8)
    【STM32F407开发板用户手册】第7章 STM32F407下载和调试方法(IAR8)
    【STM32F429开发板用户手册】第6章 STM32F429工程模板建立(IAR8)
    【STM32F407开发板用户手册】第6章 STM32F407工程模板建立(IAR8)
    【STM32F429开发板用户手册】第5章 STM32F429下载和调试方法(MDK5)
    【STM32F407开发板用户手册】第5章 STM32F407下载和调试方法(MDK5)
    基于STM32H7,F407,F429的ThreadX内核程序模板,含GCC,MDK和IAR三个版本(2020-06-08)
    【STM32F429开发板用户手册】第4章 STM32F429工程模板建立(MDK5)
    【STM32F407开发板用户手册】第4章 STM32F407工程模板建立(MDK5)
  • 原文地址:https://www.cnblogs.com/yaolin1228/p/8284939.html
Copyright © 2020-2023  润新知