Hamilton问题求解-最近邻点法和最近插入法(Python实现)

Hamilton问题求解-最近邻点法和最近插入法

一、定义

1. 哈密顿通路

G = < V , E > G=<V,E> G=<V,E>为一个图(有向图或者无向图)。 G G G中经过的每个顶点一次且仅一次的通路称为哈密顿通路。(通路不一定回到起点,但一定穿过每个顶点一次且仅一次)

2. 哈密顿回路

G = < V , E > G=<V,E> G=<V,E>为一个图(有向图或者无向图)。 G G G中经过的每个顶点一次且仅一次的回路称为哈密顿回路。(回路要求穿过每个顶点一次后回到起点)

3. 性质

  • 存在哈密顿通路(回路)的图一定是连通图
  • 哈密顿通路是初级通路,哈密顿回路是初级回路

初级是通路(回路)指除了起点和终点之外,所有的顶点和边都互不相同的通路(回路)

  • 若图 G G G中存在哈密顿回路,则它一定存在哈密顿通路
  • 只有哈密顿通路,无哈密顿回路的图不叫哈密顿图

二、判定定理

目前没有判定哈密顿图的简单充要条件

  • 设无向图 G = < V , E > G=<V,E> G=<V,E>为哈密顿图, V 1 V_1 V1 V V V的任意真子集,则 p ( G − V 1 ) ≤ ∣ V 1 ∣ p(G-V_1)\le |V_1| p(GV1)V1

p ( G − V 1 ) p(G-V_1) p(GV1)为G中删除 V 1 V_1 V1后的所得图的联通分支数目, ∣ V 1 ∣ |V_1| V1 V 1 V_1 V1集合中包含的顶点个数。
推论:有割点的图一定不是哈密顿图。
割点:类似下图,去掉 V 1 V_1 V1后连通就剩 ( V 2 , V 4 ) (V_2,V_4) (V2,V4) ( V 3 , V 5 ) (V_3,V_5) (V3,V5)两个连通分量,大于等于2,故其为割点。
在这里插入图片描述

  • G G G为n(n ≥ \ge 3)阶无向简单图(不存在平行边的无向图),若对于 G G G中的每一对不相邻的顶点u,v,均有 d ( u ) + d ( v ) ≥ n − 1 d(u)+d(v)\ge n-1 d(u)+d(v)n1,则G中存在哈密顿通路,又若 d ( u ) + d ( v ) ≥ n d(u)+d(v)\ge n d(u)+d(v)n,则G中存在哈密顿回路,即G为哈密顿图。

d(u),d(v)分别代表顶点u,v的度数。
推论:设G是n(n ≥ \ge 3)阶无向简单图,若G的最小度 ≥ n 2 \ge \frac{n}{2} 2n,则G是哈密顿图。(d1+d2) ≥ \ge n
由推论可知,对于完全图Kn,当n ≥ \ge 3时,是哈密顿图,完全二部图Kr,s 当r==s ≥ \ge 2时是哈密顿图。

  • 在n(n ≥ \ge 2)阶有向图 D = < V , E > D=<V,E> D=<V,E>中,如果略去所有有向边的方向,所得无向图中含生成子图Kn,则D中存在哈密顿通路。

推论:n(n ≥ \ge 3)阶有向完全图是哈密顿图。

三、求解算法

1. 最近邻点法

算法思想:每次将离当前顶点最近的顶点加入,一般只能找到近似解,不能找到最优解
算法步骤

  • 从网络中找一个点做为起点
  • 从剩下的点中找一个离上一个点最近的点加入
  • 重复步骤2
  • 将最后加入的点与起点连接构成回路

2.最近插入法

最近插入法(Nearest Insertion)于1977年提出,用于解决TSP问题,可以得到相对最近邻点法更优的解。
算法步骤

  • 任取一点作为整个Hamilton回路的起点,记为 v 1 v_1 v1,同时找出离 v 1 v_1 v1最近的一个顶点 v k v_k vk,形成一个子回路: v 1 → v k → v 1 v_1 \rightarrow v_k \rightarrow v_1 v1vkv1
  • 在剩下的顶点中寻找一个离子回路中的各顶点最近的顶点 v s v_s vs,并在已有子回路中找到一条边 ( v i , v j ) (v_i,v_j) (vi,vj),使得 w i s + w s j − w i j w_{is}+w_{sj}-w_{ij} wis+wsjwij最小,然后把顶点 v s v_s vs插入顶点 v i v_i vi v j v_j vj之间,用两条边 ( v i , v s ) (v_i,v_s) (vi,vs) ( v s , v j ) (v_s,v_j) (vs,vj)代替原来的边 ( v i , v j ) (v_i,v_j) (vi,vj)形成一条新的回路: v 1 → . . . → v i → v s → v j → . . . → v 1 v_1\rightarrow ...\rightarrow v_i\rightarrow v_s\rightarrow v_j\rightarrow ...\rightarrow v_1 v1...vivsvj...v1
  • 重复步骤2,直到所有的顶点都加入到子回路。此时,最后的回路就是所求的TSP的一个较好的Hamilton回路。

四、Python源码实现

Hamilton.py

import numpy as np


class HamiltonUtil:
    def __init__(self, input_matrix):
        self.graph = input_matrix
        self.point_num = np.shape(self.graph)[0]
        self.HamSolve = []
        self.HamLength = 0

    def search_min(self, index, matrix):
        min_val = np.float('inf')
        for i in matrix:
            if self.graph[index][i - 1] < min_val:
                min_val = self.graph[index][i - 1]
        return min_val

    def find_match_vex(self, index, match_val):
        ret_index = 0
        for i in self.graph[index]:
            if i != match_val:
                ret_index += 1
            else:
                break
        return ret_index

    def find_index(self, vec, value):
        index = 0
        for i in vec:
            if i != value:
                index += 1
            else:
                break
        return index
    def clear_stack(self):
        self.HamSolve = []
        self.HamLength = 0

    def neibor_point(self):
        self.clear_stack()
        start = 1
        V = np.arange(1, self.point_num + 1, 1)
        self.HamSolve.append(start)
        V = np.delete(V, start - 1)
        BetweenPoint = start
        while np.shape(V)[0] != 0:
            VWeight = self.search_min(BetweenPoint - 1, V)
            Next = self.find_match_vex(BetweenPoint - 1, VWeight) + 1
            self.HamSolve.append(Next)
            V = np.setdiff1d(V, Next)
            self.HamLength = self.HamLength + VWeight
            BetweenPoint = Next
        self.HamSolve.append(start)
        self.HamLength = self.HamLength + self.graph[Next - 1][start - 1]

    def nearest_insertion(self):
        self.clear_stack()
        start = 1
        V = np.arange(1, self.point_num + 1, 1)
        self.HamSolve.append(start)
        V = np.setdiff1d(V, self.HamSolve)
        BetweenPoint = start
        VWeight = self.search_min(BetweenPoint - 1, V)
        Next = self.find_match_vex(BetweenPoint - 1, VWeight) + 1
        self.HamSolve.append(Next)
        self.HamSolve.append(start)
        V = np.setdiff1d(V, Next)
        self.HamLength = self.HamLength + VWeight + self.graph[Next - 1][start - 1]
        BetweenPoint = Next

        while np.shape(V)[0] != 0:
            HamPoint = list(set(self.HamSolve))
            NearestPoint = 0
            NearWeight = np.zeros((len(HamPoint),), dtype=float)
            NearPoint = np.zeros((len(HamPoint),), dtype=int)
            for i in range(len(HamPoint)):
                NearWeight[i] = self.search_min(HamPoint[i] - 1, V)
                NearPoint[i] = self.find_match_vex(HamPoint[i] - 1, NearWeight[i]) + 1
            NearestPoint = NearPoint[self.find_index(NearWeight, np.min(NearWeight))]
            HamIncrement = np.zeros((len(self.HamSolve) - 1,), dtype=float)
            for i in range(len(self.HamSolve) - 1):
                HamIncrement[i] = self.graph[self.HamSolve[i] - 1][NearestPoint - 1] + \
                                  self.graph[NearestPoint - 1][self.HamSolve[i + 1] - 1] - \
                                  self.graph[self.HamSolve[i] - 1][self.HamSolve[i + 1] - 1]
            MinHamIncrement = np.min(HamIncrement)
            InsertPoint = self.find_index(HamIncrement, MinHamIncrement) + 1
            self.HamSolve.insert(InsertPoint, NearestPoint)
            self.HamLength += MinHamIncrement
            V = np.setdiff1d(V, NearestPoint)

五、运行测试实例

main.py

from Hamilton import HamiltonUtil
import numpy as np
if __name__ == '__main__':
    E = np.array([[np.float('inf'), 10, 6, 8, 7, 15],
                  [10, np.float('inf'), 5, 20, 15, 16],
                  [6, 5, np.float('inf'), 14, 7, 8],
                  [8, 20, 14, np.float('inf'), 4, 12],
                  [7, 15, 7, 4, np.float('inf'), 6],
                  [15, 16, 8, 12, 6, np.float('inf')]], dtype=float)
    neibor_point = HamiltonUtil(E)
    # 最邻近点法
    neibor_point.neibor_point()
    print(neibor_point.HamSolve)
    print(neibor_point.HamLength)
    E = np.array([[np.float('inf'), 10, 6, 8, 7, 15],
                  [10, np.float('inf'), 5, 20, 15, 16],
                  [6, 5, np.float('inf'), 14, 7, 8],
                  [8, 20, 14, np.float('inf'), 4, 12],
                  [7, 15, 7, 4, np.float('inf'), 6],
                  [15, 16, 8, 12, 6, np.float('inf')]], dtype=float)
    nearest_insertion = HamiltonUtil(E)
    # 最近插值法
    nearest_insertion.nearest_insertion()
    print(nearest_insertion.HamSolve)
    print(nearest_insertion.HamLength)

  • 5
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Moresweet猫甜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值