哈密顿环的实现

哈密顿环

DFS

  1. 数据结构

    class Node(object):
        def __init__(self):
            self.way= None
            self.node= None
    
  2. 步骤

    1. 构建一个栈S,栈中初始状态只含有初始节点0的节点类(Node(0,[])).
    2. 每次从栈顶弹出一个节点 i。
      1. 当节点i的编号为0,回到出发节点,而且i.way符合要求(每个节点只经过一次,最后回到初始点0),输出路径。如果i.way不符合要求,舍弃不操作。
      2. 当节点i的编号不为0,如果i.way符合要求(每个节点经过一次),则将i的孩子节点以及路径压入栈中。如果i.way不符合要求,舍弃不操作。
    3. 重复2的操作,当栈为空时候,说明没有可行解,程序终止。

BFS

  1. 数据结构

    class Node(object):
        def init(self):
            self.way= None
            self.node= None
    
  2. 步骤:

    1. 构建一个队列Q,队列中初始状态只含有初始节点0的节点类(Node(0,[])).
    2. 每次取队头的第一个节点 i。
      1. 当节点i的编号为0,回到出发节点,而且i.way符合要求(每个节点只经过一次,最后回到初始点 0),输出路径。如果i.way不符合要求,舍弃不操作。
      2. 当节点i的编号不为0,如果i.way符合要求(每个节点经过一次),则将i的孩子节点以及路径压入队列Q中。如果i.way不符合要求,舍弃不操作。
    3. 重复2的操作,当队列为空时候,说明没有可行解,程序终止。

爬山法

  1. 数据结构

       class Node(object):
        def init(self):
            self.way= None
               self.cost = 0
            self.node= None
    
  2. 步骤

    1. 构建一个栈S,栈中初始状态只含有初始节点0的节点类(Node(0,[])).
    2. 每次从栈顶弹出一个节点 i。
      1. 当节点i的编号为0,回到出发节点,而且i.way符合要求(每个节点只经过一次,最后回到初始点0),输出路径。如果i.way不符合要求,舍弃不操作。
      2. 当节点i的编号不为0,如果i.way符合要求(每个节点经过一次),将i的孩子节点按照路径加权距离大到小排序,然后依次将i的孩子节点压入栈中。如果i.way不符合要求,舍弃不操作。
    3. 重复2的操作,当栈为空时候,说明没有可行解,程序终止。

最小哈密顿环

分支界限法

  1. 分支界限法可以用于求解优化问题。 特点:利用已经得到的可行解,剪除不能得到优化解的分支。
  2. 两个要素:
    1. 产生可行解的策略:使用采用爬山法得到第一个可行解,整个过程采用最佳优先策略。
    2. 剪除分支的策略: 判断以x为根节点可行解代价是否大于已知可行解的最小代价。绑定函数,具体判断。
  3. 数据结构

       class Node(object):
        def init(self):
            self.way= None
               self.cost = 0
            self.node= None
    
  4. 步骤:

    1. 哈密顿环的可行解方法得到一个可行解,记录其代价为C*。
    2. 构建一个最小堆Heap,按照节点类的cost进行排序调整,初始状态只含有开始节点0的节点类。
    3. 每次从Heap弹出最小的节点i
      1. 当节点i的编号为0,回到出发节点,而且i.way符合要求(每个节点只经过一次,最后回到初始点0),记录输出路径和代价C’,更新可行解代价C* = min(C*,C’)。如果i.way不符合要求,舍弃不操作。
      2. 当节点i的编号不为0,如果i.way符合要求(每个节点经过一次),将i的孩子节点,然后依次将i的孩子节点压入最小堆中,并对堆进行调整。如果i.way不符合要求,舍弃不操作。
    4. 重复步骤3, 直至最小堆为空,输出记录下来的最小代价C*以及对应的路径。

关键代码

DFS:

def DFS(s,cur,way,M,n):
    ham = False
    if (M[cur][s] == 1) and isall(n,way):
        print way
        return True
    for i in range(n):
        #未访问过的一个邻结点
        if (M[cur][i]) and (isvi(i,way) == False):
            way.append(i)
            print way
            #递归搜索
         ham=DFS(s,i,way,M, n)
            if ham:
                break
            way.pop()
    return ham

BFS:

def BFS(s,M,n):
    Q = deque()
    Q.append(s)
    while len(Q) != 0:
        cur = Q.popleft()
        if (s.data == cur.data) and isall(n,cur.pathway):
            print cur.pathway
            return True
        for i in range(n):
            if M[cur.data][i] and isvi(i,cur.pathway) == False:
               way=cur.pathway
            way.append(cur.data)
               t=Node_a(i, way)
                Q.append(t)
    return False

爬山法:

def Climb_DMF(curPath, curCost):
    global minPath, minCost, disMa, priMa
    n = len(disMa[0])
    #当前代价超过最小代价剪枝
    if curCost >= minCost:
        return
    #与(a)不同,当走过所有节点后还需回到初始节点!!!
    if len(curPath) == n:
        e = curPath[-1]
        nexPath = curPath[:]
        nexPath.append(curPath[0])
        Climb_DMF(nexPath, disMa[e][curPath[0]]+curCost)
    #构成哈密顿环
    elif len(curPath) > n:
        minCost = curCost
        minPath = curPath[:]
        return
    #未遍历完,选择节点
    else:
        #爬山法,优先选择代价小的候选节点
        for i in range(n):
            e = curPath[-1]
            index = priMa[e][i]
            if index not in curPath:
                nexPath = curPath[:]
                nexPath.append(index)
                Climb_DMF(nexPath, disMa[e][index]+curCost)

分支界限法:

def __build__(self, cur):
        print '当前边集:',cur.edge,'\t当前最小代价:',
        if self.minNode == None:
            print float('inf'),
        else:
            print self.minNode.cost,
        edge = cur.selectCandidate()
        #叶节点
        if len(edge) == 0:
            #哈密顿环
            if cur.graph.size == 0:
            #if cur.isCircle:
                print '\t形成哈密顿环:','代价:',cur.cost,
                if self.minNode == None:
                    self.minNode = cur.copy()
                    print '\t获得第一个可行解'
                elif self.minNode.cost > cur.cost:
                    self.minNode = cur.copy()
                    print '\t更新当前最小哈密顿环'
                else:
                    print '\t代价大于当前最优解,剪枝'
        #非叶节点,递归建立
        else:
            print '未形成哈密顿环','代价:',cur.cost,
            if cur.cost==float('inf'):
                print '不能构成哈密顿环,剪枝'
            #未找到解或当前代价低于最小代价
            elif self.minNode == None or self.minNode.cost > cur.cost:
                cur.left = cur.copy()
                cur.right = cur.copy()
                cur.left.includeEdge(edge)
                cur.right.notIncludeEdge(edge)
                #print '递归建树'
                self.__build__(cur.left)
                self.__build__(cur.right)
            else:
                print '当前代价大于最小代价,剪枝'
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我可以为您提供Java实现哈密顿问题回溯法的代码。请注意,由于哈密顿问题是NP完全问题,因此这个算法的时间复杂度是指数级别的,所以它只适用于小规模的问题。 以下是Java代码: ```java import java.util.ArrayList; import java.util.List; public class HamiltonianCycle { private int[][] graph; // 图的邻接矩阵 private int[] path; // 存储当前路径 private boolean[] visited; // 存储节点是否已经被访问 private int count; // 存储哈密顿的数量 private List<Integer[]> paths; // 存储所有哈密顿的路径 public HamiltonianCycle(int[][] graph) { this.graph = graph; this.path = new int[graph.length]; this.visited = new boolean[graph.length]; this.count = 0; this.paths = new ArrayList<>(); } public void findHamiltonianCycle() { path[0] = 0; // 从节点0开始搜索 visited[0] = true; dfs(1); System.out.println("哈密顿的数量为:" + count); for (Integer[] p : paths) { System.out.println("一条哈密顿的通路为:" + arrayToString(p)); } } private void dfs(int pos) { if (pos == graph.length) { // 找到了一个哈密顿 if (graph[path[pos - 1]][path[0]] == 1) { count++; paths.add(path.clone()); } return; } for (int i = 0; i < graph.length; i++) { if (!visited[i] && graph[path[pos - 1]][i] == 1) { // 如果节点未被访问过且和上一个节点有边相连 path[pos] = i; visited[i] = true; dfs(pos + 1); visited[i] = false; } } } private String arrayToString(Integer[] arr) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < arr.length; i++) { sb.append(arr[i]); if (i != arr.length - 1) { sb.append(" -> "); } } return sb.toString(); } public static void main(String[] args) { int[][] graph = { {0, 1, 0, 1, 0}, {1, 0, 1, 1, 1}, {0, 1, 0, 0, 1}, {1, 1, 0, 0, 1}, {0, 1, 1, 1, 0} }; HamiltonianCycle hc = new HamiltonianCycle(graph); hc.findHamiltonianCycle(); } } ``` 在这个实现中,我们用一个二维数组`graph`表示图的邻接矩阵,其中`graph[i][j]`表示节点i和节点j是否有边相连。`path`数组存储当前搜索的路径,`visited`数组存储节点是否已经被访问过,`count`变量存储哈密顿的数量,`paths`列表存储所有哈密顿的路径。 在`findHamiltonianCycle`方法中,我们从节点0开始搜索,然后调用`dfs`方法进行深度优先搜索。`dfs`方法的参数`pos`表示当前搜索的路径长度,如果`pos==graph.length`说明已经找到了一个哈密顿。如果这个的最后一个节点和起点相连,则说明找到了一个哈密顿,`count`加一并将这个的路径加入`paths`列表中。否则,继续搜索。 在`dfs`方法中,我们遍历所有未被访问过的节点,如果这个节点和上一个节点有边相连,则将这个节点加入路径中,将它标记为已访问,然后递归搜索下一个节点。当递归返回时,将这个节点从路径中删除,并将它标记为未访问。 在`main`方法中,我们定义了一个例子图,并创建`HamiltonianCycle`对象进行搜索。输出结果如下: ``` 哈密顿的数量为:2 一条哈密顿的通路为:0 -> 1 -> 2 -> 4 -> 3 -> 0 一条哈密顿的通路为:0 -> 3 -> 4 -> 2 -> 1 -> 0 ``` 其中,第一行输出哈密顿的数量,第二行和第三行输出两个哈密顿的路径。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值