模拟退火算法 求解旅行商问题

在算法里面有一类问题叫做最优化问题,这类问题通常的特点是问题的解空间很大,用传统的算法没有办法穷举。
比如时间复杂度是O(N!)的问题,这类问题解空间会非常非常的大,比如在N=15的时候,就有1307674368000种可能性。

在用自己的笔记本上面计算了一下,求解15个元素的全排列,跑了没多久电脑就卡死了,然后在实验室的服务器上面试了一下,计算的用时大概是300s左右,内存占了60G左右。这已经是一个很大的开销了。

#如果你感兴趣的话,可以在本地跑一下,改变‘abcd’的大小,超过10以上,程序运行时间开始明显的上升
import itertools
for i in itertools.permutations('abcd',4):
        print (''.join(i))

对于这种复杂的组合优化问题,解空间往往非常大,如果暴力计算的话,往往是需要计算几十甚至是几百个元素的全排列。刚刚在计算15的全排列的时候,已经开销已经非常大了。对于,几十几百的全排列,是一个不可思议的计算量。

so,对于这类问题,一个常见的解法是利用组合优化的算法,比如爬山法,模拟退火算法,蚁群算法等等。这类算法的核心思想是:放弃遍历所有解的尝试,而是通过遍历一部分解空间,来找到一个接近全局最优解的一个近似最优解。

模拟退火算法

模拟退火算法是一种启发式寻优算法,其出发点是基于物理中固体物质的退火过程与一般组合优化问题之间的相似性。模拟退火算法从某一较高初温出发,伴随温度参数的不断下降,结合概率突跳特性在解空间中随机寻找目标函数的全局最优解,即在局部最优解能概率性地跳出并最终趋于全局最优。

模拟退火算法是通过赋予搜索过程一种时变且最终趋于零的概率突跳性,从而可有效避免陷入局部极小并最终趋于全局最优的串行结构的优化算法

image.png

如果我们现在有上面这样一个函数图,如图二所示,现在想求函数的全局最优解。如果采用贪心策略,那么从A点开始试探,如果函数值继续减少,那么试探过程就会继续。而当到达点B时,显然我们的探求过程就结束了。最终,只能找打一个局部最后解B。

模拟退火算法的搜索过程引入了随机因素。模拟退火算法以一定的概率来接受一个比当前解要差的解,因此有可能会跳出这个局部的最优解,达到全局的最优解。以上图为例,模拟退火算法在搜索到局部最优解B后,会以一定的概率接受向右继续移动。也许经过几次这样的不是局部最优的移动后会到达B 和C之间的峰点,于是就跳出了局部最小值B。

根据Metropolis准则,粒子在温度T时趋于平衡的概率为exp(-ΔE/(kT)),其中E为温度T时的内能,ΔE为其改变数,k为Boltzmann常数。Metropolis准则常表示为

image.png

Metropolis准则表明,在温度为T时,出现能量差为dE的降温的概率为P(dE),表示为:P(dE) = exp( dE/(kT) )。其中k是一个常数,exp表示自然指数,且dE<0。所以P和T正相关。这条公式就表示:温度越高,出现一次能量差为dE的降温的概率就越大;温度越低,则出现降温的概率就越小。又由于dE总是小于0(因为退火的过程是温度逐渐下降的过程),因此dE/kT < 0 ,所以P(dE)的函数取值范围是(0,1) 。随着温度T的降低,P(dE)会逐渐降低。

我们将一次向较差解的移动看做一次温度跳变过程,我们以概率P(dE)来接受这样的移动。也就是说,在用固体退火模拟组合优化问题,将内能E模拟为目标函数值 f,温度T演化成控制参数 t,即得到解组合优化问题的模拟退火演算法:由初始解 i 和控制参数初值 t 开始,对当前解重复“产生新解→计算目标函数差→接受或丢弃”的迭代,并逐步衰减 t 值,算法终止时的当前解即为所得近似最优解,这是基于蒙特卡罗迭代求解法的一种启发式随机搜索过程。

用模拟算法求解旅行商问题

有 N ( <=20 ) 台 PC 放在机房内,现在要求由你选定一台 PC,用共 N-1 条网线从这台机器开始一台接一台地依次连接他们,最后接到哪个以及连接的顺序也是由你选定的,为了节省材料,网线都拉直。求最少需要一次性购买多长的网线。

"""
模拟退火算法
"""
import numpy as np
import math
import matplotlib.pyplot as plt
import random
import copy

#calu_city_length 计算的是城市0到城市1,城市1到城市2,... ,城市18到城市19,城市19到城市0,组成一个环的距离
#为什么要这么连接?因为这里做了一个coding上面的调整,假设城市之间的连接关系是不能调整的,只能按照city0到city1...city18到city19,city19到city0的关系连接。但是,在后面调参的时候,需要调整的是城市之间的连接顺序
def calu_city_length(city):
    sum_distance=0
    for i in range(len(city)-1):
        x_diff=city[i][0][0]-city[i+1][0][0]
        y_diff=city[i][0][1]-city[i+1][0][1]
        distance= math.sqrt(x_diff*x_diff+y_diff*y_diff)
        sum_distance += distance
    #计算city[n-1]-city[0]的距离
    distance=math.sqrt( (city[len(city)-1][0][0]-city[0][0][0])**2 + (city[len(city)-1][0][1]-city[0][0][1])**2 )
    sum_distance+=distance
    return sum_distance

def show(city):
    x_list=[]
    y_list=[]
    for i in range(len(city)):
        x=city[i][0][0]
        y=city[i][0][1]
        x_list.append(x)
        y_list.append(y)
    plt.plot(x_list,y_list)
    plt.show()


def perturb(city):
    a=range(len(city))
    c1,c2=random.sample(a,2)
    temp_x=city[c1][0][0]
    temp_y=city[c1][0][1]
    city[c1][0][0]=city[c2][0][0]
    city[c1][0][1]=city[c2][0][1]   
    city[c2][0][0]=temp_x
    city[c2][0][1]=temp_y
    return city


def sa(city,temperature):
    cost=[]
    while temperature >0.001:
        for i in range(100):
            len1=calu_city_length(city)
            #扰动
            orignal_city=copy.deepcopy(city)
            #perturb 函数里面把city 已经修改了,结果是city与perturb_city是相等的
            perturb_city=perturb(city)
            len2=calu_city_length(perturb_city)

            delta=len2-len1
            if (delta <0):   #新路线好与旧路线
                city=perturb_city
            else:
                #以一定的概率接收较差的解
                r=random.random()
                if math.exp(((-delta)/temperature)) > r:
                    city=perturb_city
                else:
                    city=orignal_city
        temperature=float(temperature) * 0.99
        cost.append(calu_city_length(city))
    return city,cost            


if __name__=="__main__":
    #城市的个数
    n=20
    temperature=2000

    #随机初始化城市的坐标
    #所有的城市都是连通的,城市之间的距离就是坐标的距离
    city=np.random.randint(1,100,size=(n,1,2))

    #访问第20城市的坐标
    #坐标x:city[19][0][0]
    #坐标y:city[19][0][1]

    city,cost=sa(city,temperature)
    plt.plot(cost)
    plt.show()
    print (calu_city_length(city))  
运行结果:

如果把每一次的代价输出的话,那么结果如下,横坐标的迭代的次数,纵坐标是将所有城市连通的总代价。cost很明显的随着程序的运行的次数在下降,然后收敛在某个值。

2017-09-24 20-53-21屏幕截图.png

PS:
在今年的数学建模里面,我们team就用的是这个算法,但是用之前一直不是很确定模拟退化的算法会不会在模型的算法里面生效。直到程序运行的结果出来,算法成功收敛!!!开心到爆炸!!!

参考资料:
https://zhuanlan.zhihu.com/p/23968011
http://blog.csdn.net/kai940325/article/details/43267917

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容

  • 卷首语 几天前把刚买的《证明达尔文》看完了。没有即可就写书评,主要是因为手头上的事太多了,各种各样的事情。今天在外...
    LostAbaddon阅读 3,504评论 7 34
  • 前几天在群里无意中聊到一些灵异经历,六六颇感兴趣,追着让我讲故事。 如果你觉得天方夜谭或是觉得这个世界有这样一个存...
    桃酥1618阅读 854评论 0 2
  • 买个竹篮吧。 街边两只可爱的小狗 谁知道下面这个是干什么用的? 皮影戏:猪八戒背媳妇。 入迷 古镇留下我的背影 听...
    李小宛阅读 588评论 0 1
  • [TOC] 常用抓取命令 安装 使用准备 设备需要root权限 tcpdump 二进制文件 wireshark 分...
    木猫尾巴阅读 34,176评论 3 6