zoukankan      html  css  js  c++  java
  • 回溯法 | 旅行商问题(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 }
  • 相关阅读:
    C# WinForm dataGridView 技巧小结
    Win7设置局域网共享
    vs2010快捷键大全
    C# WebBrowser.DocumentCompleted 多次调用解决方法
    为应用程序池 'DefaultAppPool' 提供服务的进程关闭时间超过了限制
    VB高清图标制作方法
    sqlite 中文排序
    一个vbs文件将指定文件夹下的文件名输出到指定文件夹下
    用DOS命令获取文件列表
    文件搜索神器 Everything
  • 原文地址:https://www.cnblogs.com/TQCAI/p/7660789.html
Copyright © 2011-2022 走看看