[问题]某推销员要到若干城市去推销商品,各城市之间的路程如下图所示。他要选定一条从驻地1出发,经过每个城市一次,最后回到驻地的路线,并使总路程最短。
[解析]将该问题的解空间组织如下:
这棵解空间树中从根节点B到任一叶节点的路径均定义了图的一条周游路线,而图的每一条周游路线都恰好对应于解空间树中从根节点B到某一叶节点的路径。
最后从根节点B开始,对解空间树进行DFS。所选用的剪枝函数为判断当前已花费的路程是否小于当前已找到的最短周游路径的长度,属于限界函数。搜索过程中每到达一个叶节点,则记录当前周游路径的总路程,并与已找到的最小值进行比较,根据比较结果来更新最小值。
代码如下:
// 推销员当前所在的城市,初始化为出发地1
static int currentLocation = 1;
// 存储各城市之间距离,其中i地与j地之间的距离为distance[i][j],n=3
static int distance[n+1][n+1];
// 标识第i站(i从0开始)为哪个城市,即当前路径在解空间树中层次为i的节点处选择的子链接代表的是哪个城市,其中根节点的层次为0,数组初始化为{2,3,4}
static int station[n];
// 存储当前已找到的最优周游路线
static int optimal[n];
// 当前已找到的最短路程,初始化为正无穷大
static int minTotalDiatance = MAX_INFINITY;
// 当前已花费的路程,初始化为0
static int distanceGone = 0;
// 对解空间树中层次为i的当前节点进行DFS
void BackTrack(int i)
{
// 检查是否已到达叶节点
if(i == n)
{
// 如果已到达叶节点,则对当前路径所表示的周游方案进行处理
if(distanceGone < minTotalDiatance)
{
// 存储当前已找到的最优周游方案
Copy(station,optimal,n);
// 更新最短路程
minTotalDiatance = distanceGone;
}
}
else // 如果尚未到达叶节点,则沿着当前节点的各条子链接分别进行DFS
{
for(int j = i;j < n;j++)
{
distanceGone += distance[currentLocation][station[j]];
// 检查当前节点的当前子节点是否满足限界条件,即当前已花费的路程是否小于当前已找到的最短周游路径的长度
if(distanceGone < minTotalDiatance)
{
// 如果满足,则推进到当前节点的当前子节点
Exchange(station,i,j);
// 对新的当前节点进行DFS
BackTrack(i + 1);
// 对新的当前节点进行DFS完毕后,回溯到其父节点,即原来的当前节点
Exchange(station,i,j);
distanceGone -= distance[currentLocation][station[j]];
}
else
{
// 如果不满足,则直接回溯到当前节点
distanceGone -= distance[currentLocation][station[j]];
}
}
}
}