//回溯法解决旅行售货员问题
template<class Type>
class Traveling
{
friend Type TSP(int **,int [],int,Type);
friend void main(void);
public:
Type BBTSP(int v[]);
private:
void Backtrack(int i);
int n, //图G的顶点数
*x, //当前解
*bestx; //当前最优解
Type **a, //图G的邻接矩阵
cc, //当前费用
bestc, //当前最优值
NoEdge; //无边标记
};
template<class Type>
void Traveling<Type>::Backtrack(int i)
{
if(i==n)
{
if(a[x[n-1]][x[n]]!=NoEdge&&a[x[n][1]!=NoEdge&&
cc+a[x[n-1]][x[n]]+a[x[n]][1]<bestc||bestc==NoEdge))
for(int j=1;j<=n;j++)
bestx[j]=x[j];
bestc=cc+a[x[n-1]][x[n]]+a[x[n]][1];
}
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]);
}
}
}
template<class Type>
Type TSP(Type **a,int v[],int n,Type NoEdge)
{
Traveling<Type> Y;
//初始化Y
Y.x=new int[n+1];
//置x为单位排列
for(int i=1;i<=n;i++)
Y.x[i]=i;
Y.a=a;
Y.n=n;
Y.bestc=NoEdge;
Y.bestx=v;
Y.cc=0;
Y.NoEdge=NoEdge;
//搜索x[2:n]的全排列
Y.Backtrack(2);
delete []Y.x;
return Y.bestc;
}
template<class Type>
class MinHeapNode
{
friend Traveling<Type>;
public:
operator Type() const
{
return lcost;
}
private:
Type lcost, //子树费用的下界
cc, //当前费用
rcost; //x[s:n-1]中顶点最小出边费用和
int s, //根结点到当前结点的路径为x[0:s]
*x; //需要进一步搜索的顶点是x[s+1:n-1]
};
template<class Type>
Type Traveling<Type>::Backtrack(int v[])
{
//定义最小堆的容量为1000
MinHeap<MinHeapNode<Type>> H(1000);
Type *MinOut=new Type[n+1];
//计算MinOut[i]=顶点i的最小出边费用
Type MinSum=0;//最小出边费用和
for(int i=1;i<=n;i++)
{
Type Min=NoEdge;
for(int j=1;j<=n;j++)
if(a[i][j]!=NoEdge&&(a[i][j]<Min||Min==NoEdge))
Min=a[i][j];
if(Min==NoEdge) return NoEdge;//无回路
MinOut[i]=Min;
MinSum+=Min;
}
//初始化
MinHeapNode<Type> E;
E.x=new int[n];
for(int i=0;i<n;i++)
E.x[i]=i+1;
E.s=0;
E.cc=0;
E.rcost=MinSum;
Type bestc=NoEdge;
//搜索排列空间树
while(E.s<n-1)
{
//非叶结点
if(E.s==n-2)
{
//当前扩展结点是叶结点的父结点
//再加2条边构成回路
//所构成回路是否优于当前解
if(a[E.x[n-2]][E.x[n-1]]!=NoEdge&&
a[E.x[n-1]][1]!=NoEdge&&(E.cc+
a[E.x[n-2]][E.x[n-1]]+a[E.x[n-1]][1]
<bestc||bestc==NoEdge))
{
bestc=E.cc+a[E.x[n-2]][E.x[n-1]]+a[E.x[n-1]][1];
E.cc=bestc;
E.lcost=bestc;
E.s++;
H.Insert(E);
}
else delete []E.x;
else
{
//产生当前扩展结点的儿子结点
for(int i=E.s+1;i<n;i++)
if(a[E.x[E.s]][E.x[i]]!=NoEdge)
{
//可行儿子结点
Type cc=E.cc+a[E.x[E.s]][E.x[i]];
Type rcost=E.rcost-MinOut[E.x[E.s]];
Type b=cc+rcost; //下界
if(b<bestc||bestc==NoEdge)
{
//子树可能含最优解
//结点插入最小堆
MinHeapNode<Type> N;
N.x=new int[n];
for(int j=0;j<n;j++)
N.x[j]=E.x[j];
N.x[E.s+1]=E.x[i];
N.x[i]=E.x[E.s+1];
N.cc=cc;
N.s=E.s+1;
N.lcost=b;
N.rcost=rcost;
H.Insert(N);
}
}
delete []E.x;
}
try
{
H.DeleteMin(E));
}
catch(OutOfBounds)
{
break;
}
}
if(bestc==NoEdge)
return NoEdge;
for(int i=0;i<n;i++)
v[i+1]=E.x[i];
while(true)
{
delete []E.x;
try
{
H.DeleteMin(E);
}
catch(OutOfBounds)
{
break;
}
}
return bestc;
}