旅行售貨員問題


一、問題描述

某售貨員要到若干城市去推銷商品,已知各城市之間的路程(或旅費)。他要選定一條從駐地出發,經過每個城市一次,最后回到駐地的路線,使總的路程(或總旅費)最小。

        如下圖: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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM