用贪婪算法解决邮差问题

作者: 不如葱油饼 | 来源:发表于2018-02-23 11:33 被阅读222次

    现在想起大二的时候的离散数学仍是心有余悸。现已时隔多年,依稀记得邮差问题还有一个贪婪算法。主要是简单易懂吧。但是一说起来,难度刚好的把才学的matplotlib库拿来练习。国安民乐,岂不美哉?
    首先准备一下贪婪算法的基本思想:

    在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解。

    贪婪算法不是对所有问题都能得到整体最优解,关键是贪婪策略的选择,选择的贪婪策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。

    接着自己给自己设计题目:

    要求26个地点,要求最短路径走完所有的点,并绘制路线图。太难了不敢做,先从简单做起吧。

    one出题

    那么首先我们首先随机生成26个点吧,不然手写得到啥时候去。还要出题的时候偷懒了。26个点,就26个字母表示吧

    import random
    name = 'abcdefghijklmnopqrstuvwxyz'
    points = {}
    for i in name:
        x = random.randint(0, 100)
        y = random.randint(0, 100)
        points[i] = (x, y)
    

    这里随机生成0-100的xy坐标,记录到points中去,这个字典我们打印出来就是这个样子。
    {'a': (90, 65), 'b': (15, 12)...

    two距离计算函数

    现在,有一个动作会重复计算,那就是计算两点距离,那就写一个函数,这样每次用就方便了

    def len_point(x, y):
        a = (y[0] - x[0]) ** 2
        b = (y[1] - x[1]) ** 2
        c = a + b
        length = round(c ** 0.5, 2)
        return length
    

    这应该是初中内容,那就没啥说的了。只是要注意这是针对我们的坐标格式写的,要针对不同情况不同写。

    three开始计算距离

    首先我们要走几次肯定是知道的

    times = len(points) - 1  
    

    复制一个列表方便我们瞎折腾,可不能把这个表搞乱了。
    建一个列表存路径,一个列表存每次走的距离。
    然后第一步还是要我们确定的,那就定A点吧。

    points_c = points.copy()
    min_p_group = ["a"]  # 给出一个列表存路径
    min_d_group = []  # 储存每次走的距离
    first_p = points_c["a"]  # 给出第一个点
    del points_c['a']  # 删除第一个点
    

    那么方法就是循环26次,每一次计算该点与剩下点的距离,找到最小值。把该点记录到路径中,再从原列表删除该点。

    for i in range(0, times):
        key_points = []
        for key in points_c.keys():
            key_points.append(key)  # 计算还要走几个点
    
        min_p = len_point(first_p, points[key_points[0]])  # 第一步
        p_number = 0  # 重置点位置
        for i in range(0, len(points_c)):
            length = len_point(first_p, points[key_points[I]])
            if length < min_p:
                min_p = length  # 储存最短路径
                p_number = i  # 储存最短路径的位置
        min_p_group.append(key_points[p_number])  # 将最短路径的位置保存
        min_d_group.append(min_p)
        first_p = points_c[key_points[p_number]]  # 将最短路径位置保存下一个开始
        del points_c[key_points[p_number]]  # 从字典里删除这个点
    

    好了,现在最短路径已经存在min_p_group中了,顺便我也记了下每次的距离在min_d_group ,就是这样

    ['a', 'v', 'd', 'p', 'j', 'x'...
    [6.08, 12.53, 9.06, 8.54...
    

    four画图

    再复制个列表画图用。
    准备搞两张图,一张光画点,一张连起来。
    因为知道matplotlib是要用到xy坐标的,所以先见p_x,p_y两个列表准备用。

    import matplotlib.pyplot as plt
    points_d = points.copy()
    p_x = []  # 储存x坐标
    p_y = []  # 储存y坐标
    

    第一张图我们就随便画了只要把所有点画上去就好了所以画图的参数用‘o',顺便也把尺寸啊,名字什么的定一下,

    for value in points_d.values():
        x = value[0]
        p_x.append(x)
        y = value[1]
        p_y.append(y)
    plt.subplots(2,2,figsize=(10,5))#规定两张图的尺寸
    plt.subplot(121)  # 第一张图
    for key in points_d.keys():
        plt.annotate(key, xy=points_d[key])#给每个点标注
    plt.plot(p_x, p_y, 'o')
    

    第二张图呢就稍微复杂一点,每两点之间画一次。

    plt.subplot(122)  # 第二张图
    plt.title("TPS routes")
    for key in points_d.keys():
        plt.annotate(key, xy=points_d[key])
    for i in range(0, times):
        plt.plot([points_d[min_p_group[i]][0], points_d[min_p_group[i + 1]][0]],
                 [points_d[min_p_group[i]][1], points_d[min_p_group[i + 1]][1]], '-o')
    

    five大功告成

    plt.show() 
    

    这样我们就得到了一张路线图,感觉还是可以的哈。


    路线路

    six总结

    这次用到代码的都是很基础的东西,用到的理论也实在是令我一个数学系的产品狗汗颜,自然代码的写法也是相当稚嫩。
    这算是我第一篇关于代码的文字,是沿着前面的登山者留下来的帐篷和继续向上延伸的脚印。当我可能到达某个高度时再回首这个标记可能哑然失笑,不过那肯定是会心的。

    相关文章

      网友评论

      本文标题:用贪婪算法解决邮差问题

      本文链接:https://www.haomeiwen.com/subject/rewtxftx.html