問題描述
某售貨員要到若干城市去推銷商品,已知各城市之間的路程(旅費),他要選定一條從駐地出發,經過每個城市一遍,最後回到駐地的路線,使總的路程(總旅費)最小。
解空間
解空間:排列樹
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
*/