旅行售货员问题

一、问题描述

某售货员要到若干城市去推销商品,已知各城市之间的路程(或旅费)。他要选定一条从驻地出发,经过每个城市一次,最后回到驻地的路线,使总的路程(或总旅费)最小。

如下图:1,2,3,4 四个城市及其路线费用图,任意两个城市之间不一定都有路可达。

  

二、问题理解

1.分支限界法利用的是广度优先搜索和最优值策略。

2.利用二维数组保存图信息a[MAX_SIZE][MAX_SIZE]

其中a[i][j]的值代表的是城市i与城市j之间的路径费用

一旦一个城市没有通向另外城市的路,则不可能有回路,不用再找下去了

下面是书上介绍的一种方法,书里面有一些错误,经过修改可以得出正确答案了;具体通过代码分析:

package essay;

import java.util.PriorityQueue;

public class BBTSP {

    public static float [][]a;

    private static class MinHeap extends PriorityQueue<HeapNode>{
        public MinHeap() {
            super();
        }

        public void put(HeapNode node) {
            add(node);
        }

        public HeapNode removeMin() {
            HeapNode poll = poll();
            return poll;
        }
    }

    private static class HeapNode implements Comparable{

        float lcost,   //子树费用下界
        cc,            //当前费用
        rcost;         //x[s:n-1]中定点最小出边费用和
        int s;
        //相当于计数器,表示在当前解答树的第几层;
        int[] x;

        public HeapNode(float lc, float ccc, float rc, int ss, int[] xx) {
            lcost = lc;
            cc = ccc;
            rcost = rc;
            s = ss;
            x = xx;
        }
        @Override
        public int compareTo(Object x) {
            float xlc = ((HeapNode)x).lcost;
            if(lcost < xlc)return -1;
            if(lcost == xlc)return 0;
            return 1;
        }

    }

    public static float bbTsp(int v[]){
        int n = v.length - 1;
        MinHeap heap = new MinHeap();
        float[] minOut = new float[n + 1];
        float minSum = 0;
        for(int i = 1; i <= n; i++){
            float min = Float.MAX_VALUE;
            for(int j = 1; j <=n; j++){
                if(a[i][j] < min){
                    min = a[i][j];
                }
            }
            if(min == Float.MAX_VALUE)
                return Float.MAX_VALUE;
            minOut[i] = min;
            minSum += min;
        }
        int[] x = new int[n];
        int[] minx = new int[n];
        for(int i = 0; i < n; i++)x[i] = i+1;
        HeapNode enode = new HeapNode(0, 0, minSum, 0, x);
        float bestc = Float.MAX_VALUE;
        while(enode != null && enode.s < n - 1){
            x = enode.x;
            if(enode.s == n - 2){
                if(a[x[n - 2]][x[n - 1]] < Float.MAX_VALUE
                        && a[x[n - 1]][1] < Float.MAX_VALUE
                        && enode.cc + a[x[n - 2]][x[n - 1]] + a[x[n - 1]][1] < bestc ){
                    bestc  = enode.cc + a[x[n - 2]][x[n - 1]] + a[x[n - 1]][1];
                    enode.cc = bestc;
                    enode.lcost = bestc;
                    //System.out.println(x[0]+","+x[1]+","+x[2]+","+x[3]);
                    enode.s++;
                    minx = x;
                    heap.put(enode);
                }
            }
            else{
                for(int i = enode.s + 1; i < n; i++){
                    if(a[x[enode.s]][x[i]] < Float.MAX_VALUE){
                        float cc = enode.cc + a[x[enode.s]][x[i]];
                        float rcost = enode.rcost - minOut[x[enode.s]];
                        float b = cc + rcost;
                        //更新当前费用,最小出边费用和,子树费用下界;
                        //子树费用下界,也就是当前最小的可能解
                        if(b < bestc){
                            int[] xx = new int[n];
                            for(int j = 0; j < n; j++)xx[j] = x[j];
                            xx[enode.s + 1] = x[i];
                            xx[i] = x[enode.s + 1];
                            //访问到i节点,将i节点与enode.s+1节点交换位置复制给xx;
                            HeapNode node = new HeapNode(b, cc, rcost, enode.s+1, xx);
                            heap.put(node);
                        }
                    }
                }
            }
            enode = (HeapNode)heap.removeMin();
        }
        for(int i = 0; i < n; i++){

            v[i + 1] = minx[i];
        }
        return bestc;
    }

}

先介绍这个BBTSP类:
BBTSP的构成:

  1.类MinHeap继承了priority_queue也就是我们要放入的优先队列;

  2.类HeapNode这个是我们自定义的一个数据结构,放在优先队列中;

  3.bbTsp是本问题的解决类

  4.a是邻接矩阵,作为我们要解决问题的图;

 解决问题的思想:

  用最小堆表示活结点优先队列,最小堆中最小元素是HeapNode,中的lcost作为子树费用下界,cc为当前费用,rcost是剩余点的最小出边费用和,s记录当前在解答树的第几层,x数组存储最优解;广度优先遍历,子树费用下界作为最小堆的排列依据,每次取到enode(当前最优解)for循环儿子结点,得到最优可行子树儿子解,结点插入最小堆;当遍历到最后一个结点的时候,比较得到最小回到1城市的最优解;注意最优解要单独存放在minx数组中,课本上写的有些问题;

测试代码:

package essay;
import org.junit.*;
public class MyTest {

    @Test
    public void test() {
        BBTSP bbtsp = new BBTSP();
        bbtsp.a = new float[5][5];
        bbtsp.a[1][1] = 0;
        bbtsp.a[1][2] = 30;
        bbtsp.a[1][3] = 8;
        bbtsp.a[1][4] = 7;

        bbtsp.a[2][1] = 30;
        bbtsp.a[2][2] = 0;
        bbtsp.a[2][3] = 4;
        bbtsp.a[2][4] = 5;

        bbtsp.a[3][1] = 8;
        bbtsp.a[3][2] = 4;
        bbtsp.a[3][3] = 0;
        bbtsp.a[3][4] = 10;

        bbtsp.a[4][1] = 7;
        bbtsp.a[4][2] = 5;
        bbtsp.a[4][3] = 10;
        bbtsp.a[4][4] = 0;

        int[] v = new int[5];
        System.out.println("最小费用是:" + bbtsp.bbTsp(v));
        System.out.println("路径是: ");
        for(int i = 1; i <= 4; i++){
            System.out.printf("%d-->", v[i]);
        }
        System.out.println(1);
    }
}

来源:http://www.cnblogs.com/handsomecui
欢迎访问:handsomecui.top

时间: 2024-11-08 10:10:48

旅行售货员问题的相关文章

哈密尔顿回路(旅行售货员问题)的回溯算法

1. 回溯法的基本原理: 回溯算法也叫试探法,它是一种系统地搜索问题的解的方法.回溯算法的基本思想是:从一条路往前走,能进则进,不能进则退回来,换一条路再试.用回溯算法解决问题的一般步骤为: 1.定义一个解空间,它包含问题的解. 2.利用适于搜索的方法组织解空间. 3.利用深度优先法搜索解空间. 4.利用限界函数避免移动到不可能产生解的子空间. 问题的解空间通常是在搜索问题的解的过程中动态产生的,这是回溯算法的一个重要特性. 2.旅行售货员问题的回溯算法实现 算法具体实现主要代码如下: // T

旅行售货商问题 -- 回溯法

/*旅行售货员问题回溯法*/ #include<stdio.h> #define N 4 int cc,//当前路径费用 bestc;//当前最优解费用 int a[N+1][N+1];//邻接矩阵,存放图的信息 int bestx[N+1];//当前最优解 int x[N+1];//当前解 void inputAjac() { int i,j; printf("输入大于0的值表示有边,小于0表示无边:\n"); for(i=1;i<=N;i++) { for(j=i

回溯法 -数据结构与算法

1.回溯法算法思想: 定义: 回溯法(探索与回溯法)是一种选优搜索法,按选优条件向前搜索,以达到目标.但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”. 1.回溯法适用:有许多问题,当需要找出它的解集(全部解)或者要求回答什么解是满足某些约束条件的最优解时,往往要使用回溯法. 2.有组织的穷举式搜索:回溯法的基本做法是搜索或者有的组织穷尽搜索.它能避免搜索所有的可能性.即避免不必要的搜索.这种方

算法期末考试练习题

一.选择题 1.算法分析中,记号O表示(B),记号?标售(A),记号Θ表示(D) A 渐进下界 B 渐进上界 C 非紧上界 D 紧渐进界 E 非紧下界 2.以下关于渐进记号的性质是正确的有:(A) A  f(n) =Θ(g(n)),g(n) =Θ(h(n)) ⇒f(n) =Θ(h(n)) B  f(n) =O(g(n)),g(n) =O(h(n)) ⇒h(n) =O(f(n)) C  O(f(n))+O(g(n)) = O(min{f(n),g(n)}) D  f(n) = O(g(n)) ⇔g

NP难问题求解综述

NP难问题求解综述 摘要:定义NP问题及P类问题,并介绍一些常见的NP问题,以及NP问题的一些求解方法,最后最NP问题求解的发展方向做一些展望.   关键词:NP难问题 P类问题 算法 最优化问题   正文: 一.NP难问题及P类问题 为了解释NP难问题及P类问题,先介绍确定性算法和非确定性算法这两个概念,设A是求解问题Π的一个算法,如果在算法的整个执行过程中,每一步只有一个确定的选择,则称算法A是确定性(Determinism)算法.设A是求解问题Π的一个算法,如果算法A以如下猜测并验证的方式

五类常见算法小记 (递归与分治,动态规划,贪心,回溯,分支界限法)

近日复习了一些算法知识,小记于此 递归与分治法 直接或间接地调用自身的算法称为递归算法. 递归是算法设计与分析中常用的一种技术,描述简单且易于理解. 分治法的设计思想是将一个规模为n难以解决的问题分解为k个规模较小的子问题,这些子问题相互独立且与原问题相同. 递归地解这些子问题,然后将各子问题的解合并得到原问题的解. 典型例子:Fibonacci数列,阶乘,Hanoi塔:二分法搜索.快速排序.合并排序. 动态规划法 动态规划过程是:根据当前(阶段)状态,采取相应的决策,引起状态的转移.如下图,一

二、五大常用算法的简单介绍

1.递归与分治 递归算法:直接或者间接不断反复调用自身来达到解决问题的方法.这就要求原始问题可以分解成相同问题的子问题. 示例:阶乘.斐波纳契数列.汉诺塔问题 斐波纳契数列:又称黄金分割数列,指的是这样一个数列:1.1.2.3.5.8.13.21.--在数学上,斐波纳契数列以如下被以递归的方法定义:F1=1,F2=1,Fn=F(n-1)+F(n-2)(n>2,n∈N*)). 分治算法:待解决复杂的问题能够简化为几个若干个小规模相同的问题,然后逐步划分,达到易于解决的程度. 1.将原问题分解为n个

回溯法小实例

1.图的m着色问题: 1 /* 2 *问题描述:给定无向连通图G和m种不同的颜色.用这些颜色为图G的各个顶点着色,每个顶点着一种颜色.是否有一种着色法使G中每条边的两个顶点着不同的颜色. 3 * 这个问题是图的m可着色判定问题.若一个图最少需要m中颜色才能使图中每条边连接的2个顶点着不同的颜色,则称这个数m为该图的色数. 4 *算法分析:给定图G=(V,E)和m中颜色,如果这个图不是m可着色,给出否定回答:如果这个图是m可着色的,找出所有不同的着色法. 5 * 回溯法+子集树 6 * 问题的解空

回溯法与分支限界

回溯法 1.有许多问题,当需要找出它的解集或者要求回答什么解是满足某些约束条件的最佳解时,往往要使用回溯法. 2.回溯法的基本做法是搜索,或是一种组织得井井有条的,能避免不必要搜索的穷举式搜索法.这种方法适用于解一些组合数相当大的问题. 3.回溯法在问题的解空间树中,按深度优先策略,从根结点出发搜索解空间树.算法搜索至解空间树的任意一点时,先判断该结点是否包含问题的解.如果肯定不包含(剪枝过程),则跳过对该结点为根的子树的搜索,逐层向其祖先结点回溯:否则,进入该子树,继续按深度优先策略搜索. 问