旅行售货员问题 / TSP / 排列树 (c++详解)

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

提供三个例子供测试。

  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值