算法分析 | 回溯法 | 旅行商问题

Elizabeth ·
更新时间:2024-09-21
· 679 次阅读

一.问题分析

1.问题描述:一个联通无向图中,求最短路径回路.也就是求出一个最佳序列,并且终点和起点有直接路径.

2.问题分析:

     ① 约束条件:因为存在着两个结点不直接相连的情况,有些序列一开始就不可能出现.约束函数存在

记录连接情况的二维数组 T[ t - 1 ][ i ] !=  \infty           // t-1表示上一个结点; i表示全部剩余节点

      ②限界函数:现有距离+上一站到某个分支的距离优于现有最优值.  当最优解是最小值时,它的初值应该设为 \infty 

当前距离 cn + 新增距离T[ x[t-1] ][ x[i] ] < 一次递归最优解 bestn      //如果误写成T[ t - 1 ][ i ],意味着解序列是默认的{0,1,2,3...}

      ③具有递归问题中的元素全排列性质, 存在代码结构:        一般来说,还要在Backtrack( t + 1 )前存储当前值,以便回溯

Backtrack( t )

{

...

  for (int i = t; i < N; i++)

  {

      swap(i,t);            //a[i]表示全部剩余元素, t表示子问题的队首a[t]

      Backtrack(t+1);

      swap(i,t);

  }

}

二.代码实现

分为三部分

1.全局变量定义. 

      ①在实际中,"\infty" 用C++自带的常量INT_MAX表示.

      ②顺便一提,二维vector输出行数:T.size();  输出每一行列数T[i].size();

2.递归函数

      ①使用首位为0的方式计算,A[0]表示起点,从A[1]位开始递归

3.初始化/调用递归函数/打印结果   3 in 1

//TSP is short of "Traveling Salesman Problem" ,旅行商问题 const int M4 = 5; const int INF = INT_MAX; vector<vector>T1= //一个5*5的二维数组 { {INF,3,INF,8,9}, {3,INF,3,10,5}, {INF,3,INF,4,3}, {8,10,4,INF,20}, {9,5,3,20,INF} }; int cn3; //记录当前值 vector cx3(M4, 0); //记录当前序列 int bestn3; //记录一次递归结束后最优值 vector bestx3(M4, 0); //记录一次递归结束后最优策略 void TSPbacktrack(int t) //默认起点是0,t从 1 开始求解 { //先写终止条件 if (t >= M4 && //遍历队尾元素,到达叶结点 T1[ 0 ][ cx3[M4-1] ]!=INF && //cx3[]已得出一个解序列,如果结点 0 (起点)和cx3[n-1](终点)相通 cn3 + T1[ 0 ][ cx3[M4 - 1] ]起点距离 } else { for (int i = t; i < M4; i++) { if (T1[ cx3[ t - 1 ] ][ cx3[ i ] ] != INF && //当前分支中某结点与上一站相通 且 cn3 + T1[ cx3[ t - 1 ] ][ cx3[ i ] ] < bestn3) //现有距离+上一站到某个分支的距离优于现有最优值 { swap(cx3[i], cx3[t]); //将选中的该结点与子问题的队首交换 cn3 += T1[ cx3[ t - 1] ][ cx3[ t ] ]; //已选中该结点,更新当前值 TSPbacktrack(t + 1); //递归求解N-1子问题 cn3 -= T1[cx3[ t - 1 ] ][ cx3[ t ] ]; //递归完该结点,恢复当前值 /*①*/ swap(cx3[i], cx3[t]); //回溯 } } } } void TSP() { //初始化 cn3 = 0; //当前初始值=0 /*②*/bestn3 = INF; //求最小值,一次递归最优值的初始值=无穷大 for (int i = 0; i < M4; i++) { cx3[i] = i; //默认序列是0,1,2,3.... } //运算 TSPbacktrack(1);//默认起点是点0,从点1开始 //输出结果 cout << "最优旅行顺序: "; for (int i = 0; i < M4; i++) { cout << bestx3[i] << "-"; }cout << "0"; cout << endl; cout << "最短里程: " << bestn3; }

三.BUG分析

主要集中在"解序列"和"默认序列"的差异上

Bug①处:原错误语句:

swap(i, t);                     

修正后:

swap(x[ i ],x[ t ]);                          //交换的是序列

Bug②处:原错误语句

bestn3 = 0;                                 //当最优值是一个最小值时,它的初值应该=\infty               


作者:IronBull_Zhang



旅行 旅行商问题 回溯法 算法

需要 登录 后方可回复, 如果你还没有账号请 注册新账号