分支限界法的旅行商问题(TSP)
旅行推销员问题( 英语:Travelling salesman problem, TSP)是这样一个问题:给定一系列城市和每对城市之间的距离,求解访问每一座城市一次并回到起始城市的最短回路。它是组合优化中的一个NP困难问题,在运筹学和理论计算机科学中非常重要。
分支限界法在上一篇Blog中我有简单说明,并给出了基于分支界限法的Dijkstra ,这篇文章里介绍一下基于分支限界法的TSP算法。
对于TSP,我们需要利用上界和下界来对BFS进行剪枝,通过不断更新上界和下界,尽可能的排除不符合需求的child,以实现剪枝。最终,当上限和下限等同时,我们可以获得最优的BFS解,以解决TSP问题。
在第一篇中,我们用dfs获取上界,用每行矩阵最小值来获取下界。
代码如下,下面代码中,我采用贪心法(使用DFS暴力搜索到一个结果)来获取最初的上界,通过累加每行旅行商矩阵中的最小值来获取一个下界。
// MinTraveling.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include<queue>
using namespace std;
template<class Type>
class MinHeapNode
{
template<class Type>
friend class Traveing;
public:
operator Type ()const { return lcost; }
private:
Type lcost,//下限
cc,
rcost;//当前的费用
int s,
* x;
};
template<class Type>
class Traveing
{
friend int main(void);
public:
Type BBTSP(int v[]);
private:
int n;
Type** a,
cc,
bestc,
NoEdge;
};
template<class Type>
Type Traveing<Type>::BBTSP(int v[])
{
priority_queue<MinHeapNode<Type>, vector<MinHeapNode<Type>>, greater<MinHeapNode<Type>>> priority;
Type MinSum = 0;
Type* MinOut = new Type[n + 1];
for (int i = 0; i < 4; i++)
{
Type Min = NoEdge;
for (int j = 0; j < 4; j++)
if (a[i][j] != NoEdge && (a[i][j] < Min || Min == NoEdge))
Min = a[i][j];
MinOut[i] = Min;
MinSum += Min;
}
MinHeapNode<Type> E;
E.x = new Type[n + 1];
for (int i = 0; i < 5; i++)
E.x[i] = i;
E.s = 0;
E.rcost = MinSum;
E.cc = 0;
Type bestc = NoEdge;
while (E.s<n-1)
{
if (E.s == n - 2)
{
if (a[E.x[E.s]][E.x[E.s + 1]] != NoEdge && a[E.x[E.s + 1]][0] != NoEdge &&
(bestc == NoEdge || E.cc + a[E.x[E.s]][E.x[E.s + 1]] + a[E.x[E.s + 1]][0] < bestc))
{
bestc = E.cc + a[E.x[E.s]][E.x[E.s + 1]] + a[E.x[E.s + 1]][0];
E.cc = bestc;
//E.x[E.s+1] = E.x[E.s + 1];
E.s++;
E.lcost = bestc;
priority.push(E);
}
else
{
delete[] E.x;
}
}
else
{
for (int i = E.s + 1; i < n; i++)
{
if (a[E.s][i] != NoEdge)
{
Type cc = E.cc + a[E.s][i];
Type rcost = E.rcost - MinOut[E.x[E.s]];
Type b = cc + rcost;
if (b < bestc || bestc == NoEdge)
{
MinHeapNode<Type> N;
N.cc = cc;
N.lcost = b;
N.rcost = rcost;
N.s = E.s + 1;
N.x = new Type[n + 1];
for (int i = 0; i <= n; i++)
N.x[i] = E.x[i];
//Type temp = N.x[E.s + 1];
N.x[E.s + 1] = E.x[i];
N.x[i] = E.x[E.s + 1];
priority.push(N);
}
}
}
delete[] E.x;
}
if (priority.empty())
break;
E = priority.top();
priority.pop();
}
if (bestc == NoEdge)
return NoEdge;
for (int i = 0; i < 5; i++)
v[i] = E.x[i];
while (true)
{
delete[] E.x;
if (priority.empty())
break;
E = priority.top();
priority.pop();
}
return bestc;
}
int main()
{
int** A;
A = new int* [4];
for (int i = 0; i < 4; i++)
A[i] = new int[4];
A[0][0] = -1, A[0][1] = 30, A[0][2] = 6, A[0][3] = 4;
A[1][0] = 30, A[1][1] = -1, A[1][2] = 5, A[1][3] = 10;
A[2][0] = 6, A[2][1] = 5, A[2][2] = -1, A[2][3] = 20;
A[3][0] = 4, A[3][1] = 10, A[3][2] = 20, A[3][3] = -1;
int v[5];
Traveing<int> traveing;
traveing.a = A;
traveing.n = 4;
traveing.NoEdge = -1;
cout << traveing.BBTSP(v) << endl;
for (int i = 0; i < 4; i++)
cout << v[i] << "\t";
cout << endl;
return 0;
}