问题描述
某售货员要到若干城市去推销商品,已知各城市之间的路程(旅费),他要选定一条从驻地出发,经过每个城市一遍,最后回到驻地的路线,使总的路程(总旅费)最小。
解空间
解空间:排列树
x=[1 2 3……n]
相应的排列树由x[1:n]的所有排列构成
思路
旅行商问题的解空间是一棵排列树。对于排列树的回溯搜索与生成1,2,3…n的所有排列的递归算法Perm相似。
初始的时候x=[1,2,3,…n].。
在递归算法getmincost()中,当i==n时,当前遍历到了排列树的叶子节点的上一层节点(即n-1层),这个时候要判断第n-1个点与第n个点以及第n个点与第1个点之间是否形成一条回路,如果形成一条回路,则可以判断当前回路的cost是否小于目前最优值,进而判断是否更新最优值和最优解。
当i<n的时候,还没有遍历到判断n个顶点是否形成回路。这个时候能够遍历当前节点的条件是当前节点i与上一节点i-1连通(即从第一个节点一直到第i个节点形成了一条路径),并且这条路径的长度小于当前最优值,否则不遍历当前节点(约束函数)。
输入
输入第一行为一个整数n,表示图的顶点数
输入第二行为一个整数k,表示图的边数
输入第3到k+3-1行表示边的信息,每一行三个数,分别表示顶点i,顶点j,i到j的路径长度a[i][j]
4
6
1 2 30
1 3 6
1 4 4
2 3 5
2 4 10
3 4 20
输出
输出有两行
第一行为最优值,表示旅行商的最短路径长度
第二行为最优解,为旅行商的顶点遍历序列
25
1 3 2 4 1
代码
#include <iostream>
using namespace std;
#include<cstring>
#include<math.h>
#define NoEdge -1
int n;//定义图的顶点个数
int a[101][101];//定义图的邻接矩阵
int x[101];//定义当前解
int bestx[101];//定义当前最优解
int bestc;//定义当前当前值
int cc;//定义当前路径长度,形成环的时候与bestc比较看能不能更新bestc
void getmincost(int i)
{
//如果访问到n个节点,要判断是否形成回路
//如果当前值优于最优值,更新最优值和最优解
if(i==n){
//形成回路的条件就是x[n-1]与x[n]连通,x[n]与x[1]连通
if(a[x[n-1]][x[n]]!=NoEdge&&a[x[n]][1]!=NoEdge){//说明形成了回路
//如果当前值优于最优值,更新最优值和最优解
//bestc=NoEdge说明还没有广搜到一条回路,那就先试着求出一个可行解
if(cc+a[x[n-1]][x[n]]+a[x[n]][1]<bestc||bestc==NoEdge){
for(int k=2;k<=n;k++)
bestx[k]=x[k];
bestc=cc+a[x[n-1]][x[n]]+a[x[n]][1];//更新最优值
}
}
return ;
}
//当前在第i层,还得继续寻找
else{
for(int j=i;j<=n;j++){
//判断是否可以进入x[j]子树
//x[i-1]与x[j]连通使得1-i层连成一条路径且累计花费优于目前最优值
//可以进入x[j]子树
//这里要做的就是交换x[i]与x[j],进入i+1层
//思想类似于n的全排列问题,递归求解
//bestc=NoEdge说明还没有广搜到一条回路,那就先试着求出一个可行解
//现在的解是x[1],x[2]...x[i]...x[j]...x[n]
if(a[x[i-1]][x[j]]!=NoEdge&&cc+a[x[i-1]][x[j]]<bestc||bestc==NoEdge){
//满足条件,可以交换
//交换之后,现在的解是x[1],x[2]...x[j]...x[i]...x[n]
swap(x[i],x[j]);
//现在的解是x[1],x[2]...x[j]...x[i]...x[n]
//此时第i个元素是==x[j]
//第j个元素是==x[i]
cc=cc+a[x[i-1]][x[i]];//更新路径的长度,进入i+1层
getmincost(i+1);
cc=cc-a[x[i-1]][x[i]];//还原路径的长度,比较x[j+1]子树
swap(x[i],x[j]);//还原之前的解
//现在的解是x[1],x[2]...x[i]...x[j]...x[n]
}
}
}
return ;
}
int main()
{
cin>>n;//输入顶点个数
int k;
memset(a,NoEdge,sizeof(a));
cin>>k;//输入边的个数;
int p,q,len;
//初始化邻接矩阵
for(int i=1;i<=k;i++){
cin>>p>>q>>len;
a[p][q]=a[q][p]=len;
}
//初始化最优解
for(int i=1;i<=n;i++)
bestx[i]=x[i]=i;
//初始化最优值
bestc=NoEdge;
cc=0;//初始化当前值为0
getmincost(2);//出发点已知
cout<<bestc<<endl;
for(int i=1;i<=n;i++)
cout<<bestx[i]<<" ";
cout<<1;
}
/*
4
6
1 2 30
1 3 6
1 4 4
2 3 5
2 4 10
3 4 20
*/