题目
某售货员要到若干城市去推销商品,已知各城市之间的路程,他要选定一条从驻地出发,经过每个城市一遍,最后回到住地的路线,使总的路程最短。
分析
该题利用回溯法求解,该解空间为一棵排列树。
我们假设初始的一条路线为x,x中的值为 1,2,3,……,n,表示该路线为由城市1依次经过城市2、3……到n后再回到城市1(当然是假设该路线存在)。如果不存在的话,我们只需改变一下这个排列的排列方式,再进行判断,所以可想而知,我们可以知道该解空间是一棵排列树。
#include <iostream>
#include <fstream>
using namespace std;
int N = 4; //图的顶点数
template <typename T>
inline void Swap(T &a, T &b);
template <typename T>
T TSP(T **a, int n);
template <typename T>
class Traveling
{
private:
void Backtrack(int i);
int n, // 图G的顶点数
*x, // 当前解
*bestx; // 当前最优解
T **a, // 图G的领接矩阵
cur_cost, // 当前费用
bestc; // 当前最优值
int NoEdge; // 无边标记
public:
friend T TSP<T>(T **a, int n);
};
template <typename T>
void Traveling<T>::Backtrack(int i)
{
if (i == n)
{
if (a[x[n - 1]][x[n]] != 0 && a[x[n]][1] != 0 &&
(cur_cost + a[x[n - 1]][x[n]] + a[x[n]][1] < bestc || bestc == 0))
{
for (int j = 1; j <= n; j++)
bestx[j] = x[j];
bestc = cur_cost + a[x[n - 1]][x[n]] + a[x[n]][1];
}
}
else
{
for (int j = i; j <= n; j++)
{
// 是否可进入x[j]子树?
if (a[x[i - 1]][x[j]] != 0 && (cur_cost + a[x[i - 1]][x[i]] < bestc || bestc == 0))
{
// 搜索子树
Swap(x[i], x[j]);
cur_cost += a[x[i - 1]][x[i]]; //当前费用累加
Backtrack(i + 1); //排列向右扩展,排列树向下一层扩展
cur_cost -= a[x[i - 1]][x[i]];
Swap(x[i], x[j]);
}
}
}
}
template <typename T>
T TSP(T **a, int n)
{
Traveling<T> Y;
Y.n = n;
Y.x = new int[n + 1];
Y.bestx = new int[n + 1];
for (int i = 1; i <= n; i++)
{
Y.x[i] = i;
}
Y.a = a;
Y.cur_cost = 0;
Y.bestc = 0;
Y.NoEdge = 0;
Y.Backtrack(2);
cout << "最短回路为:" << endl;
for (int i = 1; i <= n; i++)
{
cout << Y.bestx[i] << " --> ";
}
cout << Y.bestx[1] << endl;
delete[] Y.x;
Y.x = 0;
delete[] Y.bestx;
Y.bestx = 0;
return Y.bestc;
}
template <typename T>
inline void Swap(T &a, T &b)
{
T temp = a;
a = b;
b = temp;
}
int main()
{
cout << "请输入图的顶点数:";
cin >> N;
int **a = new int *[N + 1];
for (int i = 0; i <= N; i++)
{
a[i] = new int[N + 1];
}
cout << "图的邻接矩阵为:" << endl;
for (int i = 1; i <= N; i++)
{
for (int j = 1; j <= N; j++)
{
cin >> a[i][j];
// cout<<a[i][j]<<" ";
}
cout << endl;
}
int len = TSP(a, N);
cout << "最短回路的长为:" << len << endl;
for (int i = 0; i <= N; i++)
{
delete[] a[i];
}
delete[] a;
a = 0;
return 0;
}
/*
4
0 30 6 4
30 0 5 10
6 5 0 20
4 10 20 0
最短回路为:
1 --> 3 --> 2 --> 4 --> 1
最短回路的长为:25
*/