回溯函數的模板爲
void backtrack(int t)
{
if (t > n) output(x);
else
for (int i = t; i <= n; i++)
{
swap(x[t], x[i]);
if (constraint(t) && bound(t)) //constraint(t)爲約束函數,bound(t)爲限界函數
backtrack(t + 1);
swap(x[t], x[i]);
}
}
代碼如下
#include<iostream>
using namespace std;
#define MAX 1000
int arc[100][100], x[100], bestx[100];//bestx用來記錄最優路徑或者中途產生的暫時最優路徑,x用來記錄路徑
int length = 0, best_length = MAX, n;
void Traveling(int t)
{
int j;
if (t > n) //到達葉子結點
{
if (arc[x[n]][1] != 0 && (length + arc[x[n]][1] < best_length))//推銷員到的最後一個城市與出發的城市之間有路徑,且當前總距離比當前最優值小
{
for (j = 1; j <= n; j++)
bestx[j] = x[j];
best_length = length + arc[x[n]][1];
}
}
else //沒有到達葉子結點
{
for (j = t; j <= n; j++)//搜索擴展結點的左右分支,即所有與當前所在城市臨近的城市
{
if (arc[x[t - 1]][x[j]] != 0 && (length + arc[x[t - 1]][x[j]] < best_length))//若果第t-1個城市與第t個城市之間有路徑且可以得到更短的路線
{
swap(x[t], x[j]); //保存要去的第j個城市到x[t]中,從第j個城市出發繼續往下走(此時t爲父結點,j爲子結點)。因爲下一步遞歸的是t+1,遞歸函數裏又是t-1,就相當於把t傳了過去,有了swap這一步,就可以在遞歸函數裏從結點j繼續往下走了
length += arc[x[t - 1]][x[t]]; //路線長度增加
Traveling(t + 1); //搜索下一個城市。不能上邊沒有swap,這裏傳參數j+1。因爲若如此做,遞歸函數裏的arc[x[t - 1]][x[j]]就會直接從j往n走,如1-3-4,而實際情況可能是1-3-2-4
length -= arc[x[t - 1]][x[t]];//回溯到父結點,恢復length的數值,爲往另一個子結點走做準備
swap(x[t], x[j]);//恢復x的順序(從j子結點回溯到t父結點,爲往t的另一個子結點走做準備)
}
}
}
}
int main()
{
int i, j;
cout << "請輸入一共有幾個城市:" << endl;
cin >> n;
cout << "請輸入城市之間的距離(用0表示路不通)" << endl;
for (i = 1; i <= n; i++)//從i=1開始賦值,如此i=1就代表結點1
for (j = 1; j <= n; j++)
cin >> arc[i][j];
for (i = 1; i <= n; i++)
{
x[i] = i;
bestx[i] = 0;
}
Traveling(2);//t=2表示當前正在考慮結點1與其他結點間的路徑
cout << "城市路線:" << endl;
for (i = 1; i <= n; i++)
cout << bestx[i] << ' ';
cout << bestx[1];
cout << endl;
cout << "最短路線長度:" << endl;
cout << best_length << endl;
return 0;
}