旅行售货员问题的解空间是一颗排序树,对于排序树的回溯法搜索与生成1,2,3,4,…,n的所有排列的递归算法Perm类似,开始时,x = [1,2,…,n],则相应的排序树由x[1:n]的所有排序构成。以下解释排序算法Perm:
(1)假设Perm(1)的含义是对x = [1,2,…,n]进行排序,则Perm(i)的含义是对[i,i+1,i+2,…,n]进行排序。为了方便描述,规定一个操作P(j),表示在数组x中,第j个与第一个交换,于是得到递归关系式: Perm(i) = P(i)Perm(i+1) + P(i+1)Perm(i+1) + …+P(n)Perm(i+1)
(2)旅行售货员的回溯法Backtrack在Perm的基础上使用了剪枝函数,将无效的全排列和有效的全排列非最优的次序统统都舍去。
以下为源代码:
#include "stdafx.h"
<pre name="code" class="cpp">#include <iostream>
using namespace std;
#define N 4
#define NoEdge -1 //无边标记-1
class Traveling
{
friend double TSP(double (*a)[N+1], int n);
private:
void Backtrack(int i);
void Swap(int &x, int &y);
int n; //图G的顶点数
int *x; //当前解
int *bestx; //最优解,保存全排列中最优的解
double (*a)[N+1]; //图G的邻接矩阵
double cc; //当前费用
double bestc; //当前最优值
bool iscycle; //判断是否有回路
};
void Traveling::Backtrack(int i) //对数组x中第i起到结尾进行全排列的试探,数组x下标为0的元素保留不用
{
if(i == n) //找到符合条件的全排列
{
if (a[x[i-1]][x[i]] != NoEdge && a[x[i]][x[1]] != NoEdge && (bestc > cc + a[x[i-1]][x[i]] +a[x[i]][x[1]] || bestc == NoEdge)) //判断是否有回路、发现最优值
{
iscycle = true;
bestc = cc + a[x[i-1]][x[i]] +a[x[i]][x[1]]; //保存最优值
for (int i = 1; i <= n; i++)
{
bestx[i] = x[i]; //保存最优解
}
}
}
else
{
for (int j =i; j <= n; j++)
{
if(a[x[i-1]][x[j]] != NoEdge && (cc + a[x[i-1]][x[j]] < bestc || bestc == NoEdge))
{
Swap(x[i],x[j]);
cc += a[x[i-1]][x[i]];
Backtrack(i+1);
cc -= a[x[i-1]][x[i]];
Swap(x[i],x[j]);
}
}
}
}
void Traveling::Swap(int &x, int &y)
{
int temp;
temp = x;
x = y;
y= temp;
}
double TSP(double (*a)[N+1], int n)
{
Traveling T;
//初始化T
T.bestc = NoEdge;
T.cc = 0;
T.n = n;
T.x = new int[n+1];
T.bestx = new int[n+1];
T.a = a;
T.iscycle = false;
//置x为单位排列
for (int i = 1; i <= n; i++)
{
T.x[i] = i;
}
T.Backtrack(2); //以T.x数组中下标为1的顶点作为旅行售货员的出发点。
if (T.iscycle)
{
cout<<"旅行售货员的最优回路代价:"<<T.bestc<<endl<<"旅行售货员的最优回路路径:";
for (int i = 1; i <= n; i++)
{
cout<<T.bestx[i]<<" ";
}
cout<<1<<endl;
}
else
cout<<"图中无回路"<<endl;
system("pause");
delete [] T.x;
delete [] T.bestx;
return T.bestc;
}
int _tmain(int argc, _TCHAR* argv[])
{
//对图a的初始化
double a[N+1][N+1];
a[1][2] = 30; //30
a[1][3] = 6;
a[1][4] = 4;
a[2][3] = 5;
a[2][4] = NoEdge; //10
a[3][4] = 20;
for (int i = 1; i <= N; i++)
{
for (int j = i + 1; j<= N; j++)
{
a[j][i] = a[i][j];
}
}
TSP(a, N);
return 0;
}
运行结果如下:
旅行售货员的最优回路代价:25
旅行售货员的最优回路路径:1 3 2 4 1