#include "cstdio"
#include "queue"
#include "cstring"
#define MAX 20
#define NoEdge 0
using namespace std;
int n; //城市个数
int v[MAX]; //路径
struct Node
{
int lcost; //子树费用下界
int cc; //当前费用
int rcost; //x[s:n-1]中顶点最小出边费用和
int s; //根结点到当前结点的路径为x[0:s]
int *x; //需要进一步搜索的顶点是x[s+1:n-1]
//子树费用下界较小的结点出队列
bool operator < (const Node &node) const
{
return lcost > node.lcost;
}
};
priority_queue<Node> pq;
int TSP(int **a)
{
int *minOut = new int[n+1]; //最小出边费用
int min = NoEdge;
int minSum = 0; //最小出边费用和
int i, j;
//记录每个顶点的最小出边费用
for(i=1; i<=n; i++)
{
min = NoEdge;
for(j=1; j<=n; j++) //如果顶点i与下一个顶点相邻其出边费用更小
if(a[i][j] != NoEdge && (a[i][j]<min || min==NoEdge))
min = a[i][j]; //更新最小出边费用
if(min == NoEdge)
return NoEdge; //没有回路
minOut[i] = min; //顶点i的最小出边费用
minSum += min; //最小出边费用增加
}
//初始化
Node E;
E.s = 0; //顶点编号
E.x = new int[n];
for(i=0; i<n; i++)
E.x[i] = i+1;
E.cc = 0; //当前费用
E.rcost = minSum; //剩余最小出边费用和
int best = NoEdge; //最优值
//搜索解空间树
while(E.s<n-1) //当没有到达叶结点时
{
if(E.s==n-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]<best || best==NoEdge))
{
best = E.cc+a[E.x[n-2]][E.x[n-1]]+a[E.x[n-1]][1]; //更新最优值
E.cc = best; printf("%d ", best);
E.lcost = best;
E.s++;
pq.push(E); //叶结点的父结点入队列
}
else
delete []E.x; //舍弃扩展结点
}
else //产生扩展结点的儿子结点
{
//检查每一个与当前结点相连的结点,将其入队列
int i;
for(i=E.s+1; i<n; i++) //注意这里i != n,因为x[i]中存放的是i+1
{
if(a[E.x[E.s]][E.x[i]]!=NoEdge) //如果下一个顶点可达
{
int cc = E.cc+a[E.x[E.s]][E.x[i]]; //当前费用
int rcost = E.rcost - minOut[E.x[E.s]]; //剩余费用
int b = cc + rcost; //最小费用下界
if(b<best || best==NoEdge) //如果可能产生最小费用
{
Node node;
node.cc = cc; //当前费用
node.s = E.s+1; //顶点编号
node.rcost = rcost; //剩余费用
node.lcost = b; //最小费用下界
int j;
node.x = new int[n];
for(j=0; j<n; j++)
node.x[j] = E.x[j];
node.x[E.s+1] = E.x[i]; //新结点路径扩展,x[E.s+1],x[i]是下一条边
node.x[i] = E.x[E.s+1];
pq.push(node);
}
}
}
delete []E.x; //完成结点扩展
}//else结束
//取下一个扩展结点
if(pq.empty())
break;
E = pq.top();
pq.pop();
}//while结束
if(best==NoEdge) //没有回路
return NoEdge;
//将最优解复制到v[]中
for(i=0; i<n; i++)
v[i] = E.x[i];
//释放所有结点
while(true)
{
delete []E.x;
if(pq.empty())
break;
E = pq.top();
pq.pop();
}
return best;
}
int main()
{
n = 4;
int **a = new int *[n+1];
int i, j;
for(i=0; i<=n; i++)
a[i] = new int[n+1];
int b[5][5] = {
{0, 0, 0, 0, 0},
{0, 0, 30, 6, 4},
{0, 30, 0, 5, 10},
{0, 6, 5, 0, 20},
{0, 4, 10, 20, 0}
};
for(i=0; i<=n; i++)
for(j=0; j<=n; j++)
a[i][j] = b[i][j];
printf("城市个数:%d\n", n);
printf("邻接矩阵:\n");
for(i=1; i<=n; i++)
{
for(j=1; j<=n; j++)
printf("%d\t", a[i][j]);
printf("\n");
}
int best = TSP(a);
printf("最短回路长为:%d\n", best);
printf("路径为:\n");
for(i=0; i<n; i++)
{
printf("%d-->", v[i]);
}
printf("%d", v[0]);
printf("\n");
return 0;
}
旅行售货员问题
最新推荐文章于 2022-11-08 23:16:41 发布