1、代码
详解都在注释里
#include<iostream>
#define N 100
using namespace std;
int n,m,w; //图的顶点数和边数
int graph[N][N]; //图的加权邻接矩阵
int nowc=0; //当前费用
int bestc=-1; //当前最优值
int x[N]; //当前解
int bestx[N]; //当前最优解
void backtrack(int k);
void swap(int &a,int &b);
void input();
void output();
int main()
{
input();
backtrack(2);
output();
}
void swap(int &a,int &b)//改变地址,真正的改变对应的值,可谓釜底抽薪
{
int temp=a;
a=b;
b=temp;
}
void input(){
int i,j;
cout<<"How much points? ";
cin>>n;
cout<<"How much edges? ";
cin>>m;
for(i=1;i<=n;i++)//先把graph数组全部赋值-1,后面再手动输入边的权值
{
for(j=1;j<=n;j++)
graph[i][j]=-1;
}
cout<<"startEdge-endEdege-weight"<<endl;
for(int k=1;k<=m;k++)
{
cin>>i>>j>>w;
graph[i][j]=w;
graph[j][i]=w;//无向图
}
for(i=1;i<=n;i++)
{
x[i]=i;
}
}
void backtrack(int k)//这里的k代表第k步去的城市,而不是代号为k的城市,因为第一个节点是出发点,那么第二步就是到达的第二个城市进行决策,因此从backtrack(2)开始
{
if(k==n)//k能走到n,说明n前面的都已经赋值通过层层语句到达了这里,故直接判断bestc
{
if( graph[x[n-1]][x[n]]!=-1 && graph[x[n]][1]!=-1 && (nowc+graph[x[n-1]][x[n]]+graph[x[n]][1]<bestc||bestc==-1) )
{ //顶点n-1到顶点n之间有边,且顶点n到顶点1之间有边,且nowc加上他们两个边权值小于bestc,则更新bestc
bestc=nowc+graph[x[n-1]][x[n]]+graph[x[n]][1];
for(int i=1;i<=n;i++)
{
bestx[i]=x[i];
}
}
return ;
}
else//k<n
{
for(int i=k;i<=n;i++)//搜索第k层所以子树
{
if( graph[x[k-1]][x[i]]!=-1 && (nowc+graph[x[k-1]][x[i]]<bestc || bestc==-1))//有边且(边的权值加上nowc小于bestc,或初始),则进入子树x[i]
{
swap(x[i],x[k]);
nowc+=graph[x[k-1]][x[k]];//假设是backtrack(3),则swap(x[3],x[3])没什么变化,然后nowc+,进入backtrack(4)
//swap(4,4)没啥,然后跳出backtrack(4),复原nowc和swap,此时for执行i++,那么swap(x[4],x[3]),此时x[4]=3,x[3]=4
//那么nowc+=graph[x[3-1]][x[3]]=graph[x[2]x[3]],注意x[3]变成4了,所以是nowc+=graph[2][4],改变路径了!!!!
//nowc是nowc+=graph[x[k-1]][x[k]],以k的上一个城市k-1为出发点,去寻找下一个到达的城市k,通过swap改变x[k],也就
//改变要到达的下一个城市,backtrack(k+1)后要复原,所以有nowc-=和swap再次出现
backtrack(k+1);
nowc-=graph[x[k-1]][x[k]];//还原nowc
swap(x[i],x[k]); //还原x[i]、x[j],也说明此时的backtrack行不通,得复原再找,如果前面的backtrack行得通,
//则x[i]位置也已改变,当进入if(k==n)时,用bestx[]记录改变后的x[i],那么bestx[]就是记录最优解的路径,x[i]是记录当前解
}
}
}
}
void output(){
cout<<"bestCost "<<": "<<bestc<<endl;
cout<<"bestWay: ";
for(int i=1;i<=n;i++){
cout<<bestx[i]<<" ";
}
cout<<"1"<<endl;
}
2、结果
①
点数 4
边数 6
1 2 30
2 4 10
1 4 4
1 3 6
2 3 5
4 3 20
输出
②
点数 5
边数 8
1 2 5
1 4 7
1 5 9
2 5 6
2 4 3
2 3 10
3 4 8
4 5 4
结果
③
How many points?
4
How many edges?
6
start-end-weight
1 2 5
1 3 9
1 4 4
2 3 13
2 4 2
3 4 7
bestcost: 23
bestway: 1 2 4 3 1
提供三个例子供测试。