├── README.md ├── Point.py ├── climbing_method_testdata.txt └── simulated_annealing_method.py /README.md: -------------------------------------------------------------------------------- 1 | # simulate-annealing-algorithm 2 | 模拟退火算法实现tsp最短路径问题 3 | -------------------------------------------------------------------------------- /Point.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: UTF-8 -*- 3 | """ 4 | 坐标类 5 | """ 6 | class Point: 7 | x = 0 # 横坐标 8 | y = 0 # 纵坐标 9 | 10 | 11 | def __init__(self,x,y): 12 | self.x = int(x) 13 | self.y = int(y) 14 | 15 | 16 | def printvar(self): 17 | print ("x=%d y=%d" % (self.x,self.y)) 18 | 19 | #p = Point(3,5) 20 | #p.printvar() 21 | -------------------------------------------------------------------------------- /climbing_method_testdata.txt: -------------------------------------------------------------------------------- 1 | NAME : a280 2 | COMMENT : drilling problem (Ludwig) 3 | TYPE : TSP 4 | DIMENSION: 280 5 | EDGE_WEIGHT_TYPE : EUC_2D 6 | NODE_COORD_SECTION 7 | 1 288 149 8 | 2 288 129 9 | 3 270 133 10 | 4 256 141 11 | 5 256 157 12 | 6 246 157 13 | 7 236 169 14 | 8 228 169 15 | 9 228 161 16 | 10 220 169 17 | 11 212 169 18 | 12 204 169 19 | 13 196 169 20 | 14 188 169 21 | 15 196 161 22 | 16 188 145 23 | 17 172 145 24 | 18 164 145 25 | 19 156 145 26 | 20 148 145 27 | 21 140 145 28 | 22 148 169 29 | 23 164 169 30 | 24 172 169 31 | 25 156 169 32 | 26 140 169 33 | 27 132 169 34 | 28 124 169 35 | 29 116 161 36 | 30 104 153 37 | 31 104 161 38 | 32 104 169 39 | 33 90 165 40 | 34 80 157 41 | 35 64 157 42 | 36 64 165 43 | 37 56 169 44 | 38 56 161 45 | 39 56 153 46 | 40 56 145 47 | 41 56 137 48 | 42 56 129 49 | 43 56 121 50 | 44 40 121 51 | 45 40 129 52 | 46 40 137 53 | 47 40 145 54 | 48 40 153 55 | 49 40 161 56 | 50 40 169 57 | 51 32 169 58 | 52 32 161 59 | 53 32 153 60 | 54 32 145 61 | 55 32 137 62 | 56 32 129 63 | 57 32 121 64 | 58 32 113 65 | 59 40 113 66 | 60 56 113 67 | 61 56 105 68 | 62 48 99 69 | 63 40 99 70 | 64 32 97 71 | 65 32 89 72 | 66 24 89 73 | 67 16 97 74 | 68 16 109 75 | 69 8 109 76 | 70 8 97 77 | 71 8 89 78 | 72 8 81 79 | 73 8 73 80 | 74 8 65 81 | 75 8 57 82 | 76 16 57 83 | 77 8 49 84 | 78 8 41 85 | 79 24 45 86 | 80 32 41 87 | 81 32 49 88 | 82 32 57 89 | 83 32 65 90 | 84 32 73 91 | 85 32 81 92 | 86 40 83 93 | 87 40 73 94 | 88 40 63 95 | 89 40 51 96 | 90 44 43 97 | 91 44 35 98 | 92 44 27 99 | 93 32 25 100 | 94 24 25 101 | 95 16 25 102 | 96 16 17 103 | 97 24 17 104 | 98 32 17 105 | 99 44 11 106 | 100 56 9 107 | 101 56 17 108 | 102 56 25 109 | 103 56 33 110 | 104 56 41 111 | 105 64 41 112 | 106 72 41 113 | 107 72 49 114 | 108 56 49 115 | 109 48 51 116 | 110 56 57 117 | 111 56 65 118 | 112 48 63 119 | 113 48 73 120 | 114 56 73 121 | 115 56 81 122 | 116 48 83 123 | 117 56 89 124 | 118 56 97 125 | 119 104 97 126 | 120 104 105 127 | 121 104 113 128 | 122 104 121 129 | 123 104 129 130 | 124 104 137 131 | 125 104 145 132 | 126 116 145 133 | 127 124 145 134 | 128 132 145 135 | 129 132 137 136 | 130 140 137 137 | 131 148 137 138 | 132 156 137 139 | 133 164 137 140 | 134 172 125 141 | 135 172 117 142 | 136 172 109 143 | 137 172 101 144 | 138 172 93 145 | 139 172 85 146 | 140 180 85 147 | 141 180 77 148 | 142 180 69 149 | 143 180 61 150 | 144 180 53 151 | 145 172 53 152 | 146 172 61 153 | 147 172 69 154 | 148 172 77 155 | 149 164 81 156 | 150 148 85 157 | 151 124 85 158 | 152 124 93 159 | 153 124 109 160 | 154 124 125 161 | 155 124 117 162 | 156 124 101 163 | 157 104 89 164 | 158 104 81 165 | 159 104 73 166 | 160 104 65 167 | 161 104 49 168 | 162 104 41 169 | 163 104 33 170 | 164 104 25 171 | 165 104 17 172 | 166 92 9 173 | 167 80 9 174 | 168 72 9 175 | 169 64 21 176 | 170 72 25 177 | 171 80 25 178 | 172 80 25 179 | 173 80 41 180 | 174 88 49 181 | 175 104 57 182 | 176 124 69 183 | 177 124 77 184 | 178 132 81 185 | 179 140 65 186 | 180 132 61 187 | 181 124 61 188 | 182 124 53 189 | 183 124 45 190 | 184 124 37 191 | 185 124 29 192 | 186 132 21 193 | 187 124 21 194 | 188 120 9 195 | 189 128 9 196 | 190 136 9 197 | 191 148 9 198 | 192 162 9 199 | 193 156 25 200 | 194 172 21 201 | 195 180 21 202 | 196 180 29 203 | 197 172 29 204 | 198 172 37 205 | 199 172 45 206 | 200 180 45 207 | 201 180 37 208 | 202 188 41 209 | 203 196 49 210 | 204 204 57 211 | 205 212 65 212 | 206 220 73 213 | 207 228 69 214 | 208 228 77 215 | 209 236 77 216 | 210 236 69 217 | 211 236 61 218 | 212 228 61 219 | 213 228 53 220 | 214 236 53 221 | 215 236 45 222 | 216 228 45 223 | 217 228 37 224 | 218 236 37 225 | 219 236 29 226 | 220 228 29 227 | 221 228 21 228 | 222 236 21 229 | 223 252 21 230 | 224 260 29 231 | 225 260 37 232 | 226 260 45 233 | 227 260 53 234 | 228 260 61 235 | 229 260 69 236 | 230 260 77 237 | 231 276 77 238 | 232 276 69 239 | 233 276 61 240 | 234 276 53 241 | 235 284 53 242 | 236 284 61 243 | 237 284 69 244 | 238 284 77 245 | 239 284 85 246 | 240 284 93 247 | 241 284 101 248 | 242 288 109 249 | 243 280 109 250 | 244 276 101 251 | 245 276 93 252 | 246 276 85 253 | 247 268 97 254 | 248 260 109 255 | 249 252 101 256 | 250 260 93 257 | 251 260 85 258 | 252 236 85 259 | 253 228 85 260 | 254 228 93 261 | 255 236 93 262 | 256 236 101 263 | 257 228 101 264 | 258 228 109 265 | 259 228 117 266 | 260 228 125 267 | 261 220 125 268 | 262 212 117 269 | 263 204 109 270 | 264 196 101 271 | 265 188 93 272 | 266 180 93 273 | 267 180 101 274 | 268 180 109 275 | 269 180 117 276 | 270 180 125 277 | 271 196 145 278 | 272 204 145 279 | 273 212 145 280 | 274 220 145 281 | 275 228 145 282 | 276 236 145 283 | 277 246 141 284 | 278 252 125 285 | 279 260 129 286 | 280 280 133 287 | EOF 288 | -------------------------------------------------------------------------------- /simulated_annealing_method.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*-coding: UTF-8 -*- 3 | import os 4 | import sys 5 | import math 6 | import numpy as np 7 | #import matplotlib.pyplot as plt 8 | 9 | sys.path.append(r'/home/python') 10 | #sys.path.append(os.path.abspath(".")) 11 | from Point import Point 12 | from random import choice,shuffle,sample,uniform 13 | """ 14 | 本程序用于实现模拟退火算法计算 15 | 最短路径问题 16 | """ 17 | #print os.path.abspath(".") 18 | parent_dir = os.path.abspath("."); 19 | filename = parent_dir + "/climbing_method_testdata.txt"; 20 | lines = open(filename).readlines(); 21 | list=[] 22 | 23 | ## 读取数据 24 | for line in lines[6:len(lines)-1]: 25 | params = line.strip().split() 26 | point = Point(params[1],params[2]) 27 | list.append(point) 28 | # print len(list) 29 | 30 | 31 | ## 计算任意两点间的距离 32 | num = len(list) 33 | arr = [[ col for col in range(num)] for row in range(num)] 34 | 35 | valstr = "" 36 | for row in range(num): 37 | for col in range(num): 38 | if col == row: 39 | arr[row][col] = 0 40 | else: 41 | p1 = list[row] 42 | p2 = list[col] 43 | arr[row][col] = round(math.sqrt(math.pow((p1.x - p2.x),2) + math.pow((p1.y - p2.y),2)),2) ### 求欧式距离,保留2位小数 44 | 45 | ## print the matrix for check 46 | """ 47 | for row in range(num): 48 | for col in range(num): 49 | if (col+1)%10 == 0 : 50 | print valstr + "\n" 51 | valstr = "" 52 | valstr += str(arr[row][col]) + "," 53 | """ 54 | 55 | print "模拟退火算法查找最短路径:" 56 | ### 参数:最小路径的最后一个节点和邻域 57 | def valSimulateAnnealSum(curnode,nextnodeList,t): 58 | 59 | if nextnodeList == None or len(nextnodeList) < 1 : 60 | print "empty" 61 | return 0 62 | 63 | maxcost = sys.maxint 64 | retnode = 0 65 | 66 | for node in nextnodeList: 67 | # print "curnode : ",curnode ," node: " ,node ," mincost : ",mincost 68 | 69 | t *= 0.98 ## 退火因子 70 | if arr[curnode][node] < maxcost : 71 | maxcost = arr[curnode][node] 72 | retnode = node 73 | ## 以一定的概率接受较差的解 74 | else: 75 | r = uniform(0,1) 76 | if arr[curnode][node] > maxcost and t > t_min and math.exp(( arr[curnode][node] - maxcost ) / t) > r: 77 | # print " t = " ,t , "maxcost = ", maxcost , " arr = " ,arr[curnode][node], " exp = ",math.exp((arr[curnode][node] - maxcost)/t) , " r = ",r , "t_min = " ,t_min 78 | retnode = node 79 | maxcost = arr[curnode][node] 80 | return (retnode,maxcost,t) 81 | 82 | return (retnode,maxcost,t) 83 | 84 | indexList = [ i for i in range(num)] ### 原始的节点序列 85 | selectedList = [] ## 选择好的元素 86 | 87 | ### 具体思想是: 从剩余的元素中随机选择十分之一的元素,作为邻域。然后从邻域中选择一个元素作为已经构建好的最小路径的下一个节点,使得该路径 88 | mincost = sys.maxint ###最小的花费 89 | 90 | count = 0 ### 计数器 91 | t = 100 ## 初始温度 92 | t_min = 50 ## 最小温度 93 | while count < num: 94 | count += 1 95 | ### 构建一个邻域: 如果indexList中元素个数大于10个,则取样的个数为剩余元素个数的十分之一。否则为剩余元素个数对10的取余数 96 | leftItemNum = len(indexList) 97 | # print "leftItemNum:" ,leftItemNum 98 | nextnum = leftItemNum//10 if leftItemNum >= 10 else leftItemNum%10 99 | 100 | nextnodeList = sample(indexList,nextnum) ### 从剩余的节点中选出nextnum个节点 101 | 102 | if len(selectedList) == 0 : 103 | item = choice(nextnodeList) 104 | selectedList.append(item) 105 | indexList.remove(item) 106 | mincost = 0 107 | continue 108 | 109 | curnode = selectedList[len(selectedList) - 1] 110 | # print "nextnodeList:" ,nextnodeList 111 | nextnode, maxcost ,t = valSimulateAnnealSum(curnode,nextnodeList,t) ### 对待选的序列路径求和 112 | 113 | ### 将返回的路径值添加到原来的路径值上,同时,在剩余的节点序列中,删除nextnode节点 114 | mincost += maxcost 115 | indexList.remove(nextnode) 116 | selectedList.append(nextnode) 117 | 118 | print "最合适的路径为:" ,selectedList 119 | print "路径节点个数:" ,len(selectedList) 120 | print "最小花费为:" , mincost 121 | print "尝试次数:", count 122 | 123 | #### 画图 ##### 124 | #plt.figure(1) 125 | x = [] 126 | y = [] 127 | for i in selectedList : 128 | x.append(list[i].x) 129 | y.append(list[i].y) 130 | #plt.plot(x,y) 131 | #plt.show() 132 | print "x: ",x 133 | print "y: " ,y 134 | ################### 爬山法求全局最短路径 ####### 135 | ### 参数:最小路径的最后一个节点和邻域 136 | def valHillClimbSum(curnode,nextnodeList): 137 | 138 | if nextnodeList == None or len(nextnodeList) < 1 : 139 | print "empty" 140 | return 0 141 | 142 | maxcost = sys.maxint 143 | 144 | retnode = 0 145 | for node in nextnodeList: 146 | # print "curnode : ",curnode ," node: " ,node ," mincost : ",mincost 147 | if arr[curnode][node] < maxcost : 148 | maxcost = arr[curnode][node] 149 | retnode = node 150 | else: 151 | return (retnode,maxcost) 152 | 153 | return (retnode,maxcost) 154 | 155 | print "\n\n爬山法算法求全局最短路径" 156 | cost = 0 157 | slist = [] 158 | leftnodeList = [ i for i in range(num)] ### 原始的节点序列 159 | finalcost = 0 160 | count = 0 161 | while count < num: 162 | count += 1 163 | ### 构建一个邻域: 如果indexList中元素个数大于10个,则取样的个数为剩余元素个数的十分之一。否则为剩余元素个数对10的取余数 164 | leftItemNum = len(leftnodeList) 165 | nextnum = leftItemNum//10 if leftItemNum >= 10 else leftItemNum%10 166 | 167 | nodeList = sample(leftnodeList,nextnum) ### 从剩余的节点中选出nextnum个节点 168 | 169 | if len(slist) == 0 : 170 | item = choice(nodeList) 171 | slist.append(item) 172 | nodeList.remove(item) 173 | finalcost = 0 174 | continue 175 | 176 | curnode = slist[len(slist) - 1] 177 | # print "leftnodeList:" ,leftnodeList 178 | nextnode, maxcost = valHillClimbSum(curnode,nodeList) ### 对待选的序列路径求和 179 | # print "nextnode: " , nextnode ," maxcost : " ,maxcost 180 | ### 将返回的路径值添加到原来的路径值上,同时,在剩余的节点序列中,删除nextnode节点 181 | finalcost += maxcost 182 | leftnodeList.remove(nextnode) 183 | slist.append(nextnode) 184 | 185 | print "最合适的路径为:" ,slist 186 | print "路径节点个数:" ,len(slist) 187 | print "最小花费为:" , finalcost 188 | print "尝试次数:", count 189 | 190 | 191 | #### 画图 ##### 192 | #plt.figure(2) 193 | x1 = [] 194 | y1 = [] 195 | for i in slist : 196 | x1.append(list[i].x) 197 | y1.append(list[i].y) 198 | print "x1 = ",x1 199 | print "y1 = ",y1 200 | #plt.plot(x,y) 201 | #plt.show() 202 | --------------------------------------------------------------------------------