回溯法 | 旅行商問題(TSP問題)


學習鏈接:

回溯法解旅行商問題(TSP)貪心算法:旅行商問題(TSP)


 

今天早上做了無數個夢,然后被緊緊地吸附在床上。掙扎一番后爬起來,已經是9點了。然后我開始研究旅行商問題。

在一個無向圖中找到一個可以遍歷所有節點的一個最短回路。理論上說可以用全排列列出所有解的下標,然后一個一個試,時間復雜度o(n!)。但是可以用回溯法,用【約束函數】(constraint)判斷當前路徑是否連通,用【界限函數】(bound)判斷當前路徑是否比已經求得的最短路徑小。這兩個判斷任意一個不符,則做“剪枝操作”(不再對后續節點進行遍歷)。

可以看出回溯法比窮舉要高明的多。這個回溯法和八皇后問題也有一些區別。TSP問題需要構造一棵排列樹:

根節點為{0}

第一層{0,1}

第二層{0,1,2},{0,2,1}

第三層{0,1,2,3},{0,1,3,2},{0,2,1,3},{0,2,3,1},{0,3,1,2},{0,3,2,1}

……

並且回溯法要求對圖進行DFS操作,即深度優先搜索。因為需要首先首次找到最深處的節點,才能設置當前最優解,好讓后續問題能有參考。

Java代碼:

 1 public class Main {
 2 
 3     public static void main(String[] args) {
 4         int[][] adjMatrix={
 5                 {0,20,6,4},
 6                 {20,0,5,10},
 7                 {6,5,0,15},
 8                 {4,10,15,0},
 9         };
10         TSP problem=new TSP(adjMatrix);
11         
12         
13     }
14 }
15 
16 class TSP{
17     int vexnum=0;//頂點數目
18     int adjMatrix[][];
19     TSP(int[][] adjMat){
20         adjMatrix=adjMat;
21         vexnum=adjMatrix.length;
22         int init[]={0};
23         Backtrack(1,init);
24         int a;
25         a=0;
26     }
27     int bestCost=0;
28     int[] bestX;//最優解向量
29     boolean isTraverseDeep=false;
30     //回溯法遞歸
31     //初始x:[0]
32     void Backtrack(int t,int[] x){//對頂點t進行操作,父結點的解向量是x,
33         if(t>=vexnum){//解向量的第一個元素應該是初始頂點,如0,最后一個元素也是0
34             x[t]=0;//最后一個節點賦值:0。
35             constraint(x,t);
36             
37         }else{//所有頂點都解完
38             int i,j;
39             int cx[]=new int[vexnum+1];
40             for(j=0;j<t;j++) cx[j]=x[j];//拷貝父結點
41             cx[t]=t;
42             if(constraint(cx,t)) Backtrack(t+1,cx);//不交換的情況下進行遞歸
43             //不斷遞歸調用【Backtrack】,進行DFS
44             for(i=1;i<t;i++){
45                 cx=new int[vexnum+1];
46                 for(j=0;j<t;j++) cx[j]=x[j];//拷貝父結點
47                 cx[t]=t;
48                 swap(cx,i,t);
49                 if(constraint(cx,t)) Backtrack(t+1,cx);//交換的情況下進行遞歸
50             }
51         }
52     }
53     boolean constraint(int[] x,int len){//對解進行約束
54         int cost=0;
55         int i;
56         int pre=x[0];
57         for(i=1;i<=len;i++){
58             int dist=adjMatrix[pre][x[i]];
59             if(dist<=0) return false;//不連通,則為否。約束(constraint)函數
60             cost+=dist;
61             pre=x[i];
62         }
63         if(isTraverseDeep){//如果已經進行了最底部的遍歷,則對這個當前花費進行判別。界限(bound)函數
64             if(cost<bestCost){//比最優解要小
65                 if(len==vexnum){//已經遍歷完
66                     bestCost=cost;
67                     bestX=x;//設置最優解向量
68                 }
69                 return true;
70             }else return false;
71         }else if(len==vexnum){//首次遍歷到底部
72             bestCost=cost;
73             bestX=x;//設置最優解向量
74             isTraverseDeep=true;
75             return true;
76         }
77         return true;
78     }
79     private void swap(int[] nums,int a,int b){
80         int tmp=nums[a];
81         nums[a]=nums[b];
82         nums[b]=tmp;
83     }
84 }

 


免責聲明!

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



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