模擬退火算法實例(c++ 與 c# 實現)

此片文章主要參考CSDN博主裏頭的一篇文章, 將本身的理解寫下來,以方便後期的查閱。ios

 

 1、C++ 實現算法

1. 已知平面上若干點座標(xi, yi), 求平面上一點p(x, y) , 到這些點的總距離最小。dom

思路: 取全部點的均值爲目標點。計算所有點與目標點求差值的和,將目標點以必定係數朝着總和的方向移動,獲得新的目標點。url

 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\n", ans); 80 }

 

2、C# 實現代碼spa

已知空間上若干點(xi, yi, zi), 求空間上包含這些點的最小球半徑 R, 以及球心座標。.net

思路:球心與這些點的最大距離爲半徑, 球心與最大距離點生成向量,將球心朝着該向量方向移動若干距離,再計算半徑的變化。code

 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#commentsblog

相關文章
相關標籤/搜索